commit b5e39539cb97d76bbc35abe603ff16507a5ea8ef
parent 9b6b433b2ed67ac6bbc7dfaec0bd98f3394e61b5
Author: Matsuda Kenji <info@mtkn.jp>
Date: Thu, 22 Dec 2022 14:13:16 +0900
add xlib_playground2
Diffstat:
11 files changed, 705 insertions(+), 6 deletions(-)
diff --git a/data/weblog b/data/weblog
@@ -45,3 +45,27 @@
1671548400 /computer/index.html
1671548400 /index.html
1671634800 /computer/xlib_playground1.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground1.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /computer/index.html
+1671634800 /computer/xlib_playground2.html
+1671634800 /index.html
+1671634800 /computer/index.html
+1671634800 /computer/xlib_playground2.html
diff --git a/man/computer/index.html b/man/computer/index.html
@@ -2,10 +2,16 @@
<p>
Small is beautiful.
</p>
+<h2>Xlib</h2>
+<ul>
+ <li><a href="xlib_playground1.html">Xlibで遊んでみる1</a></li>
+ <li><a href="xlib_playground2.html">Xlibで遊んでみる2</a></li>
+</ul>
+
+<h2>MISC</h1>
<ul>
<li><a href="what-i-use.html">使用しているソフトウェア、ハードウェア</a></li>
<li><a href="archlinux_installation.html">Arch Linuxインストール</a></li>
<li><a href="rtx1200-qos.html">ルーター(RTX1200)のQoS機能を利用して帯域を制限した</a></li>
<li><a href="setting_up_web_server.html">Webサーバーの設定</a></li>
- <li><a href="xlib_playground1.html">Xlibで遊んでみる1</a></li>
</ul>
diff --git a/man/computer/videos/ex2.webm b/man/computer/videos/ex2.webm
Binary files differ.
diff --git a/man/computer/xlib_playground2.html b/man/computer/xlib_playground2.html
@@ -0,0 +1,225 @@
+<h1>Xlibで遊んでみる2</h1>
+<time>2022-12-16</time>
+
+<p>前回: <a href="xlib_playground1.html">Xlibで遊んでみる1</a></p>
+<p>言語はC言語である。ソースコードは\
+<a href="https://git.mtkn.jp/xlib_playground/log.html">ここ</a>にある。
+</p>
+
+<h2>FPSの固定</h2>
+<p>前のフレームからの経過時間を計測して1.0/FPSを越えるまで待機させる。\
+このときに<code>nanosleep</code>を使うとなぜか上手くいかなかった。\
+ナノ秒単位で処理できそうな名前なのに使えない。\
+多分OSのコンテクストスイッチングがどうとかいう話やと思う。\
+知らんけど。\
+組み込みとかで使うんかな?
+</p>
+
+<p>
+とりあえず<code>while</code>ループの中で\
+ひたすら時刻を読んでいる。\
+リソースの無駄遣いではないのだろうか:
+</p>
+<pre><code>#defin FPS 60
+
+int
+main(void)
+{
+ long t0, t1, dt;
+ int fps_count;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+
+ while (!quit) {
+ // fix fps
+ dt = 0;
+ while (dt < 1.0 * 1000 * 1000 * 1000 / FPS){
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t1 = ts.tv_nsec;
+ dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000;
+ }
+ // count fps.
+ fps_count++;
+ if (t1 < t0){
+ printf("fps: %u\n", fps_count);
+ fps_count = 0;
+ }
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+ }
+}
+</code></pre>
+<p>
+時刻は<code>clock_gettime()</code>で測定して1秒未満の部分: <code>tv_nsec</code>\
+だけを利用している。<code>tv_nsec</code>はナノ秒ナノで、10<sup>9</sup>を掛けている。\
+<code>dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000</code>で前回の\
+時刻と現在の時刻の少数部分を比較している。繰り上がりがあれば前回の時刻よりも\
+現在の時刻の方が小さくなるので1秒足すことで調整している。\
+</p>
+<p>
+実際のFPSの計測の部分は、フレーム毎に<code>fps_count</code>を1ずつ増やし、\
+ナノ秒が繰り上がった時点での<code>fps_count</code>を表示している。\
+</p>
+<p>
+あまり正確な方法ではないように思うが、コンパクトにまとまったのではないだろうか。\
+</p>
+
+<h2>キーボード入力の処理</h2>
+<p>キーボードからの入力を受け取る:</p>
+<pre><code>XSelectInput(display, window,
+ ExposureMask|KeyPressMask|KeyReleaseMask);
+</code></pre>
+<p>ここではキーボードのキーを押した時と離した時に<code>XEvent</code>の通知を\
+受け取るように設定した。
+</p>
+<p>
+<code>XNextEvent()</code>からひとつずつ入力を受け取ると、\
+複数のキーが同時に押された時にうまく処理できなかったので、\
+押されているキーを配列に保存しておくことにした:\
+</p>
+<pre><code>enum Keys {
+ Key_D,
+ Key_S,
+ Key_A,
+ Key_W,
+ Key_Space,
+ Num_Key, //number of keys in this enum
+};
+enum Key_State {
+ Key_Up,
+ Key_Down,
+};
+
+int key_state[Num_Key];
+</code></pre>
+
+<p>
+入力の処理は<code>handle_inputs()</code>関数内で行なう。\
+<code>A</code>、<code>S</code>、<code>D</code>、<code>W</code>\
+のうちどれかのキーが押されているとそれぞれ左、下、右、上方向に\
+速度を加算するようにした。また、<code>Q</code>が押されるか、\
+windowが破壊されると<code>quit</code>フラグを<code>1</code>にして\
+メインループから抜けるようにしている:\
+</p>
+<pre><code>int quit;
+
+void
+handle_inputs(void)
+{
+ XEvent event;
+ while (XPending(display) > 0) {
+ XNextEvent(display, &event);
+ switch (event.type) {
+ case KeyPress: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'q':
+ quit = 1;
+ break;
+ case 'd':
+ key_state[Key_D] = Key_Down;
+ break;
+ case 'a':
+ key_state[Key_A] = Key_Down;
+ break;
+ case 'w':
+ key_state[Key_W] = Key_Down;
+ break;
+ case 's':
+ key_state[Key_S] = Key_Down;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case KeyRelease: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'd':
+ key_state[Key_D] = Key_Up;
+ break;
+ case 'a':
+ key_state[Key_A] = Key_Up;
+ break;
+ case 'w':
+ key_state[Key_W] = Key_Up;
+ break;
+
+ case 's':
+ key_state[Key_S] = Key_Up;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case ClientMessage: {
+ if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
+ quit = 1;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+ vx = vy = 0;
+ if (key_state[Key_D] == Key_Down)
+ vx += 300;
+ if (key_state[Key_A] == Key_Down)
+ vx += -300;
+ if (key_state[Key_S] == Key_Down)
+ vy += 300;
+ if (key_state[Key_W] == Key_Down)
+ vy += -300;
+}
+</code></pre>
+
+<p>
+入力によって変更された速度は、<code>main()</code>関数内で次の座標を\
+計算するために使用される:
+</p>
+<pre><code>float px = 200, py = 200;
+float vx = 0, vy = 0;
+int width = 40, height = 40;
+
+int
+main(void)
+{
+ /* ... */
+ quit = 0;
+ while (!quit) {
+ handle_input()
+ /* ... */
+ px = px + vx * dt / 1000 / 1000 / 1000;
+ py = py + vy * dt / 1000 / 1000 / 1000;
+ // bind within the window
+ if (px < 0)
+ px = 0;
+ if (win_width < px + width)
+ px = win_width - width;
+ if (py < 0)
+ py = 0;
+ if (win_height < py + height)
+ py = win_height - height;
+
+ XClearArea(display, window,
+ 0, 0, // position
+ win_width, win_height, // width and height
+ False);
+ XFillRectangle(display, window, gc,
+ px, py, // position
+ width, height); // width and height
+ }
+ /* ... */
+}
+</code></pre>
+
+<h2>完成品</h2>
+<p>色を変えてみた。</p>
+<video controls>
+ <source src="videos/ex2.webm" type="video/webm">
+</video>
+
+<h2>参考</h2>
+<ul>
+<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li>
+</ul>
diff --git a/man/index.html b/man/index.html
@@ -9,6 +9,7 @@
<h2>更新履歴</h2>
<a href="/rss.xml">RSS</a>
<ul>
+<li>2022-12-22 <a href="/computer/xlib_playground2.html">Xlibで遊んでみる2</a></li>
<li>2022-12-21 <a href="/computer/xlib_playground1.html">Xlibで遊んでみる1</a></li>
<li>2022-11-23 <a href="/books/978-4-06-288451-8.html">不死身の特攻兵</a></li>
<li>2022-10-31 <a href="/journal/posts/20221031.html">大阪駅にて</a></li>
diff --git a/pub/computer/index.html b/pub/computer/index.html
@@ -25,12 +25,18 @@
<p>
Small is beautiful.
</p>
+<h2>Xlib</h2>
+<ul>
+ <li><a href="xlib_playground1.html">Xlibで遊んでみる1</a></li>
+ <li><a href="xlib_playground2.html">Xlibで遊んでみる2</a></li>
+</ul>
+
+<h2>MISC</h1>
<ul>
<li><a href="what-i-use.html">使用しているソフトウェア、ハードウェア</a></li>
<li><a href="archlinux_installation.html">Arch Linuxインストール</a></li>
<li><a href="rtx1200-qos.html">ルーター(RTX1200)のQoS機能を利用して帯域を制限した</a></li>
<li><a href="setting_up_web_server.html">Webサーバーの設定</a></li>
- <li><a href="xlib_playground1.html">Xlibで遊んでみる1</a></li>
</ul>
</article>
diff --git a/pub/computer/videos/ex2.webm b/pub/computer/videos/ex2.webm
Binary files differ.
diff --git a/pub/computer/xlib_playground2.html b/pub/computer/xlib_playground2.html
@@ -0,0 +1,229 @@
+<!DOCTYPE html>
+<html lang="ja">
+<head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
+ <link rel="stylesheet" type="text/css" href="/style.css" />
+ <link rel="icon" type="image/x-icon" href="/pics/favicon.ico" />
+ <title>Xlibで遊んでみる2</title>
+</head>
+<body>
+ <header>
+ <a href="/">主頁</a> |
+ <a href="/about.html">自己紹介</a> |
+ <a href="/journal">日記</a> |
+ <a href="/farm">農業</a> |
+ <a href="/kitchen">台所</a> |
+ <a href="/computer">コンピュータ</a> |
+ <a href="/poetry">詩</a> |
+ <a href="/books">本棚</a> |
+ <a href="https://git.mtkn.jp">Git</a>
+ </header>
+ <main>
+ <article>
+<h1>Xlibで遊んでみる2</h1>
+<time>2022-12-16</time>
+
+<p>前回: <a href="xlib_playground1.html">Xlibで遊んでみる1</a></p>
+<p>言語はC言語である。ソースコードは<a href="https://git.mtkn.jp/xlib_playground/log.html">ここ</a>にある。
+</p>
+
+<h2>FPSの固定</h2>
+<p>前のフレームからの経過時間を計測して1.0/FPSを越えるまで待機させる。このときに<code>nanosleep</code>を使うとなぜか上手くいかなかった。ナノ秒単位で処理できそうな名前なのに使えない。多分OSのコンテクストスイッチングがどうとかいう話やと思う。知らんけど。組み込みとかで使うんかな?
+</p>
+
+<p>
+とりあえず<code>while</code>ループの中でひたすら時刻を読んでいる。リソースの無駄遣いではないのだろうか:
+</p>
+<pre><code>#defin FPS 60
+
+int
+main(void)
+{
+ long t0, t1, dt;
+ int fps_count;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+
+ while (!quit) {
+ // fix fps
+ dt = 0;
+ while (dt < 1.0 * 1000 * 1000 * 1000 / FPS){
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t1 = ts.tv_nsec;
+ dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000;
+ }
+ // count fps.
+ fps_count++;
+ if (t1 < t0){
+ printf("fps: %u\n", fps_count);
+ fps_count = 0;
+ }
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+ }
+}
+</code></pre>
+<p>
+時刻は<code>clock_gettime()</code>で測定して1秒未満の部分: <code>tv_nsec</code>だけを利用している。<code>tv_nsec</code>はナノ秒ナノで、10<sup>9</sup>を掛けている。<code>dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000</code>で前回の時刻と現在の時刻の少数部分を比較している。繰り上がりがあれば前回の時刻よりも現在の時刻の方が小さくなるので1秒足すことで調整している。</p>
+<p>
+実際のFPSの計測の部分は、フレーム毎に<code>fps_count</code>を1ずつ増やし、ナノ秒が繰り上がった時点での<code>fps_count</code>を表示している。</p>
+<p>
+あまり正確な方法ではないように思うが、コンパクトにまとまったのではないだろうか。</p>
+
+<h2>キーボード入力の処理</h2>
+<p>キーボードからの入力を受け取る:</p>
+<pre><code>XSelectInput(display, window,
+ ExposureMask|KeyPressMask|KeyReleaseMask);
+</code></pre>
+<p>ここではキーボードのキーを押した時と離した時に<code>XEvent</code>の通知を受け取るように設定した。
+</p>
+<p>
+<code>XNextEvent()</code>からひとつずつ入力を受け取ると、複数のキーが同時に押された時にうまく処理できなかったので、押されているキーを配列に保存しておくことにした:</p>
+<pre><code>enum Keys {
+ Key_D,
+ Key_S,
+ Key_A,
+ Key_W,
+ Key_Space,
+ Num_Key, //number of keys in this enum
+};
+enum Key_State {
+ Key_Up,
+ Key_Down,
+};
+
+int key_state[Num_Key];
+</code></pre>
+
+<p>
+入力の処理は<code>handle_inputs()</code>関数内で行なう。<code>A</code>、<code>S</code>、<code>D</code>、<code>W</code>のうちどれかのキーが押されているとそれぞれ左、下、右、上方向に速度を加算するようにした。また、<code>Q</code>が押されるか、windowが破壊されると<code>quit</code>フラグを<code>1</code>にしてメインループから抜けるようにしている:</p>
+<pre><code>int quit;
+
+void
+handle_inputs(void)
+{
+ XEvent event;
+ while (XPending(display) > 0) {
+ XNextEvent(display, &event);
+ switch (event.type) {
+ case KeyPress: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'q':
+ quit = 1;
+ break;
+ case 'd':
+ key_state[Key_D] = Key_Down;
+ break;
+ case 'a':
+ key_state[Key_A] = Key_Down;
+ break;
+ case 'w':
+ key_state[Key_W] = Key_Down;
+ break;
+ case 's':
+ key_state[Key_S] = Key_Down;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case KeyRelease: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'd':
+ key_state[Key_D] = Key_Up;
+ break;
+ case 'a':
+ key_state[Key_A] = Key_Up;
+ break;
+ case 'w':
+ key_state[Key_W] = Key_Up;
+ break;
+
+ case 's':
+ key_state[Key_S] = Key_Up;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case ClientMessage: {
+ if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
+ quit = 1;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+ vx = vy = 0;
+ if (key_state[Key_D] == Key_Down)
+ vx += 300;
+ if (key_state[Key_A] == Key_Down)
+ vx += -300;
+ if (key_state[Key_S] == Key_Down)
+ vy += 300;
+ if (key_state[Key_W] == Key_Down)
+ vy += -300;
+}
+</code></pre>
+
+<p>
+入力によって変更された速度は、<code>main()</code>関数内で次の座標を計算するために使用される:
+</p>
+<pre><code>float px = 200, py = 200;
+float vx = 0, vy = 0;
+int width = 40, height = 40;
+
+int
+main(void)
+{
+ /* ... */
+ quit = 0;
+ while (!quit) {
+ handle_input()
+ /* ... */
+ px = px + vx * dt / 1000 / 1000 / 1000;
+ py = py + vy * dt / 1000 / 1000 / 1000;
+ // bind within the window
+ if (px < 0)
+ px = 0;
+ if (win_width < px + width)
+ px = win_width - width;
+ if (py < 0)
+ py = 0;
+ if (win_height < py + height)
+ py = win_height - height;
+
+ XClearArea(display, window,
+ 0, 0, // position
+ win_width, win_height, // width and height
+ False);
+ XFillRectangle(display, window, gc,
+ px, py, // position
+ width, height); // width and height
+ }
+ /* ... */
+}
+</code></pre>
+
+<h2>完成品</h2>
+<p>色を変えてみた。</p>
+<video controls>
+ <source src="videos/ex2.webm" type="video/webm">
+</video>
+
+<h2>参考</h2>
+<ul>
+<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li>
+</ul>
+ </article>
+
+ </main>
+ <footer>
+ <address>info(at)mtkn(dot)jp</address>
+ </footer>
+</body>
+</html>
diff --git a/pub/index.html b/pub/index.html
@@ -32,6 +32,7 @@
<h2>更新履歴</h2>
<a href="/rss.xml">RSS</a>
<ul>
+<li>2022-12-22 <a href="/computer/xlib_playground2.html">Xlibで遊んでみる2</a></li>
<li>2022-12-21 <a href="/computer/xlib_playground1.html">Xlibで遊んでみる1</a></li>
<li>2022-11-23 <a href="/books/978-4-06-288451-8.html">不死身の特攻兵</a></li>
<li>2022-10-31 <a href="/journal/posts/20221031.html">大阪駅にて</a></li>
diff --git a/pub/rss.xml b/pub/rss.xml
@@ -5,10 +5,215 @@
<description>ウェブページの更新履歴</description>
<language>ja-jp</language>
<link>https://www.mtkn.jp</link>
-<lastBuildDate>Thu, 22 Dec 2022 10:27:38 +0900</lastBuildDate>
-<pubDate>Thu, 22 Dec 2022 10:27:38 +0900</pubDate>
+<lastBuildDate>Thu, 22 Dec 2022 14:12:36 +0900</lastBuildDate>
+<pubDate>Thu, 22 Dec 2022 14:12:36 +0900</pubDate>
<docs>https://www.rssboard.org/rss-specification</docs>
<item>
+<title>Xlibで遊んでみる2</title>
+<link>https://www.mtkn.jp/computer/xlib_playground2.html</link>
+<guid>https://www.mtkn.jp/computer/xlib_playground2.html</guid>
+<pubDate>Thu, 22 Dec 2022 00:00:00 +0900</pubDate>
+<description><![CDATA[<h1>Xlibで遊んでみる2</h1>
+<time>2022-12-16</time>
+
+<p>前回: <a href="xlib_playground1.html">Xlibで遊んでみる1</a></p>
+<p>言語はC言語である。ソースコードは<a href="https://git.mtkn.jp/xlib_playground/log.html">ここ</a>にある。
+</p>
+
+<h2>FPSの固定</h2>
+<p>前のフレームからの経過時間を計測して1.0/FPSを越えるまで待機させる。このときに<code>nanosleep</code>を使うとなぜか上手くいかなかった。ナノ秒単位で処理できそうな名前なのに使えない。多分OSのコンテクストスイッチングがどうとかいう話やと思う。知らんけど。組み込みとかで使うんかな?
+</p>
+
+<p>
+とりあえず<code>while</code>ループの中でひたすら時刻を読んでいる。リソースの無駄遣いではないのだろうか:
+</p>
+<pre><code>#defin FPS 60
+
+int
+main(void)
+{
+ long t0, t1, dt;
+ int fps_count;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+
+ while (!quit) {
+ // fix fps
+ dt = 0;
+ while (dt < 1.0 * 1000 * 1000 * 1000 / FPS){
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t1 = ts.tv_nsec;
+ dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000;
+ }
+ // count fps.
+ fps_count++;
+ if (t1 < t0){
+ printf("fps: %u\n", fps_count);
+ fps_count = 0;
+ }
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+ }
+}
+</code></pre>
+<p>
+時刻は<code>clock_gettime()</code>で測定して1秒未満の部分: <code>tv_nsec</code>だけを利用している。<code>tv_nsec</code>はナノ秒ナノで、10<sup>9</sup>を掛けている。<code>dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000</code>で前回の時刻と現在の時刻の少数部分を比較している。繰り上がりがあれば前回の時刻よりも現在の時刻の方が小さくなるので1秒足すことで調整している。</p>
+<p>
+実際のFPSの計測の部分は、フレーム毎に<code>fps_count</code>を1ずつ増やし、ナノ秒が繰り上がった時点での<code>fps_count</code>を表示している。</p>
+<p>
+あまり正確な方法ではないように思うが、コンパクトにまとまったのではないだろうか。</p>
+
+<h2>キーボード入力の処理</h2>
+<p>キーボードからの入力を受け取る:</p>
+<pre><code>XSelectInput(display, window,
+ ExposureMask|KeyPressMask|KeyReleaseMask);
+</code></pre>
+<p>ここではキーボードのキーを押した時と離した時に<code>XEvent</code>の通知を受け取るように設定した。
+</p>
+<p>
+<code>XNextEvent()</code>からひとつずつ入力を受け取ると、複数のキーが同時に押された時にうまく処理できなかったので、押されているキーを配列に保存しておくことにした:</p>
+<pre><code>enum Keys {
+ Key_D,
+ Key_S,
+ Key_A,
+ Key_W,
+ Key_Space,
+ Num_Key, //number of keys in this enum
+};
+enum Key_State {
+ Key_Up,
+ Key_Down,
+};
+
+int key_state[Num_Key];
+</code></pre>
+
+<p>
+入力の処理は<code>handle_inputs()</code>関数内で行なう。<code>A</code>、<code>S</code>、<code>D</code>、<code>W</code>のうちどれかのキーが押されているとそれぞれ左、下、右、上方向に速度を加算するようにした。また、<code>Q</code>が押されるか、windowが破壊されると<code>quit</code>フラグを<code>1</code>にしてメインループから抜けるようにしている:</p>
+<pre><code>int quit;
+
+void
+handle_inputs(void)
+{
+ XEvent event;
+ while (XPending(display) > 0) {
+ XNextEvent(display, &event);
+ switch (event.type) {
+ case KeyPress: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'q':
+ quit = 1;
+ break;
+ case 'd':
+ key_state[Key_D] = Key_Down;
+ break;
+ case 'a':
+ key_state[Key_A] = Key_Down;
+ break;
+ case 'w':
+ key_state[Key_W] = Key_Down;
+ break;
+ case 's':
+ key_state[Key_S] = Key_Down;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case KeyRelease: {
+ switch (XLookupKeysym(&event.xkey, 0)) {
+ case 'd':
+ key_state[Key_D] = Key_Up;
+ break;
+ case 'a':
+ key_state[Key_A] = Key_Up;
+ break;
+ case 'w':
+ key_state[Key_W] = Key_Up;
+ break;
+
+ case 's':
+ key_state[Key_S] = Key_Up;
+ break;
+ default:
+ break;
+ }
+ } break;
+ case ClientMessage: {
+ if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
+ quit = 1;
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+ vx = vy = 0;
+ if (key_state[Key_D] == Key_Down)
+ vx += 300;
+ if (key_state[Key_A] == Key_Down)
+ vx += -300;
+ if (key_state[Key_S] == Key_Down)
+ vy += 300;
+ if (key_state[Key_W] == Key_Down)
+ vy += -300;
+}
+</code></pre>
+
+<p>
+入力によって変更された速度は、<code>main()</code>関数内で次の座標を計算するために使用される:
+</p>
+<pre><code>float px = 200, py = 200;
+float vx = 0, vy = 0;
+int width = 40, height = 40;
+
+int
+main(void)
+{
+ /* ... */
+ quit = 0;
+ while (!quit) {
+ handle_input()
+ /* ... */
+ px = px + vx * dt / 1000 / 1000 / 1000;
+ py = py + vy * dt / 1000 / 1000 / 1000;
+ // bind within the window
+ if (px < 0)
+ px = 0;
+ if (win_width < px + width)
+ px = win_width - width;
+ if (py < 0)
+ py = 0;
+ if (win_height < py + height)
+ py = win_height - height;
+
+ XClearArea(display, window,
+ 0, 0, // position
+ win_width, win_height, // width and height
+ False);
+ XFillRectangle(display, window, gc,
+ px, py, // position
+ width, height); // width and height
+ }
+ /* ... */
+}
+</code></pre>
+
+<h2>完成品</h2>
+<p>色を変えてみた。</p>
+<video controls>
+ <source src="videos/ex2.webm" type="video/webm">
+</video>
+
+<h2>参考</h2>
+<ul>
+<li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li>
+</ul>
+]]></description>
+</item>
+<item>
<title>Xlibで遊んでみる1</title>
<link>https://www.mtkn.jp/computer/xlib_playground1.html</link>
<guid>https://www.mtkn.jp/computer/xlib_playground1.html</guid>
@@ -20,6 +225,7 @@
<p>X11でGUIのプログラミングをしてみようと思い、してみた。X11用の低レベルのライブラリはXlibとxcbの二つがあるようだ。x.orgのウェブページを見てみると、Xlibは古く、xcbに置きかわりつつあるという。そのため、新しくなにかを作る場合はxcbを使うようにとのことである。ところがこのxcbはドキュメンテーションに乏しく、X11を触るのが初めての人間にはなにをどうすればいいのかほとんど分からなかった。知らない関数や構造体やらがでてきても(殆ど全部知らないものだが)、その関数なり構造体なりの説明がどこにも見当たらない。manページもない。あるのはdoxygenなるものでソースコードのコメントから自動生成したいい加減なものだけで、使いものにならない。</p>
<p>とりあえずX11のことを少しは理解してからでないと初められそうもないと思い、もう少しましな情報があるXlibから始めることにした。</p>
<p>言語はC言語である。ソースコードは<a href="https://git.mtkn.jp/xlib_playground/log.html">ここ</a>にある。
+</p>
<h2>初期設定</h2>
<p>ディスプレイを開き、ウィンドウを作成する。変数はとりあえずグローバルに宣言することにした。<code>main</code>関数はできるだけ小さくして実際の処理はそれぞれの関数にさせてみる:</p>
diff --git a/pub/sitemap.xml b/pub/sitemap.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+<url><loc>https://www.mtkn.jp/</loc><lastmod>2022-12-22</lastmod></url>
+<url><loc>https://www.mtkn.jp/computer/xlib_playground2.html</loc><lastmod>2022-12-22</lastmod></url>
<url><loc>https://www.mtkn.jp/computer/xlib_playground1.html</loc><lastmod>2022-12-22</lastmod></url>
-<url><loc>https://www.mtkn.jp/</loc><lastmod>2022-12-21</lastmod></url>
-<url><loc>https://www.mtkn.jp/computer/</loc><lastmod>2022-12-21</lastmod></url>
+<url><loc>https://www.mtkn.jp/computer/</loc><lastmod>2022-12-22</lastmod></url>
<url><loc>https://www.mtkn.jp/books/</loc><lastmod>2022-11-23</lastmod></url>
<url><loc>https://www.mtkn.jp/books/978-4-06-288451-8.html</loc><lastmod>2022-11-23</lastmod></url>
<url><loc>https://www.mtkn.jp/journal/posts/20221031.html</loc><lastmod>2022-10-31</lastmod></url>