{"id":12789,"date":"2026-09-30T01:00:00","date_gmt":"2026-09-29T16:00:00","guid":{"rendered":"https:\/\/www.webcyou.com\/?p=12789"},"modified":"2026-09-25T00:56:51","modified_gmt":"2026-09-24T15:56:51","slug":"%e3%80%90r-chr%e3%80%91rust-egui-%e3%81%a7%e3%83%95%e3%82%a1%e3%83%9f%e3%82%b3%e3%83%b3%e7%94%a8%e3%82%b9%e3%83%97%e3%83%a9%e3%82%a4%e3%83%88%e3%82%a8%e3%83%87%e3%82%a3%e3%82%bf%e3%82%92%e4%bd%9c-5","status":"publish","type":"post","link":"https:\/\/www.webcyou.com\/?p=12789","title":{"rendered":"\u3010R-CHR\u3011Rust + egui \u3067\u30d5\u30a1\u30df\u30b3\u30f3\u7528\u30b9\u30d7\u30e9\u30a4\u30c8\u30a8\u30c7\u30a3\u30bf\u3092\u4f5c\u3063\u305f\u8a71 \u305d\u306e5 \u56f3\u5f62\u30c4\u30fc\u30eb\uff08Bresenham\u30fb\u6955\u5186\u30fb\u5857\u308a\u3064\u3076\u3057\u30fb\u30b9\u30bf\u30f3\u30d7\uff09"},"content":{"rendered":"\n<p>\u3069\u3082\u3067\u3059\u3002<\/p>\n<p>\u524d\u56de\u306f\u30da\u30f3\u30c4\u30fc\u30eb\u3068\u30a2\u30f3\u30c9\u30a5\u306e\u8a2d\u8a08\u3067\u3057\u305f\u3002\u4eca\u56de\u306f\u305d\u306e\u4e0a\u306b\u4e57\u3063\u3066\u3044\u308b<strong>\u56f3\u5f62\u30c4\u30fc\u30eb<\/strong>\u3001\u3064\u307e\u308a\u76f4\u7dda\u30fb\u77e9\u5f62\u30fb\u6955\u5186\u30fb\u5857\u308a\u3064\u3076\u3057\u30fb\u30b9\u30bf\u30f3\u30d7\u306e\u5b9f\u88c5\u3092\u307e\u3068\u3081\u305f\u5f62\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>\u300c\u63cf\u753b\u30c4\u30fc\u30eb\u3092\u539a\u304f\u3057\u305f\u3044\u300d\u3068\u3044\u3046\u306e\u304c R-CHR \u3092\u4f5c\u3063\u305f\u52d5\u6a5f\u306e\u3072\u3068\u3064\u3060\u3063\u305f\u306e\u3067\u3001\u500b\u4eba\u7684\u306b\u4e00\u756a\u697d\u3057\u304b\u3063\u305f\u30d1\u30fc\u30c8\u3067\u3059\u3002\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\u591a\u3081\u3067\u3044\u304d\u307e\u3059\u3002<\/p>\n<h4>\u9023\u8f09\u306e\u76ee\u6b21<\/h4>\n<ol>\n<li>\u6982\u8981\u3068\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3<\/li>\n<li>NES \u306e CHR \u30d5\u30a9\u30fc\u30de\u30c3\u30c8\uff082BPP\uff09\u3068 iNES \u30d8\u30c3\u30c0\u3001\u30d1\u30ec\u30c3\u30c8<\/li>\n<li>egui \u3067\u7d44\u3080 3 \u30d1\u30cd\u30eb UI \u3068\u30d0\u30f3\u30af\u30d3\u30e5\u30fc<\/li>\n<li>\u30c9\u30c3\u30c8\u30a8\u30c7\u30a3\u30bf\u306e\u57fa\u790e\u3068\u30a2\u30f3\u30c9\u30a5\u8a2d\u8a08<\/li>\n<li><strong>\u56f3\u5f62\u30c4\u30fc\u30eb\uff08Bresenham\u30fb\u6955\u5186\u30fb\u5857\u308a\u3064\u3076\u3057\u30fb\u30b9\u30bf\u30f3\u30d7\uff09\uff08\u3053\u306e\u8a18\u4e8b\uff09<\/strong><\/li>\n<li>PNG \u30a4\u30f3\u30dd\u30fc\u30c8\u3068 3 \u3064\u306e\u30de\u30c3\u30d4\u30f3\u30b0\u6226\u7565<\/li>\n<li>macOS \u30cd\u30a4\u30c6\u30a3\u30d6\u30e1\u30cb\u30e5\u30fc\u30fb\u591a\u8a00\u8a9e\u5bfe\u5fdc\u30fbGitHub Actions \u3067\u306e\u30ea\u30ea\u30fc\u30b9<\/li>\n<\/ol>\n<h4>\u5171\u901a\u306e\u6d41\u308c\uff1a\u30c9\u30e9\u30c3\u30b0 \u2192 \u30d7\u30ec\u30d3\u30e5\u30fc \u2192 \u30ea\u30ea\u30fc\u30b9\u3067\u78ba\u5b9a<\/h4>\n<p>\u76f4\u7dda\u30fb\u77e9\u5f62\u30fb\u6955\u5186\uff08\u30c4\u30fc\u30eb 2\u301c7\uff09\u306f\u3001\u5168\u90e8\u540c\u3058\u6d41\u308c\u3067\u52d5\u3044\u3066\u3044\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\">\u6bce\u30d5\u30ec\u30fc\u30e0:\n  1. CHR \u304b\u3089 block \u3092\u30c7\u30b3\u30fc\u30c9\uff08\u73fe\u5728\u306e\u78ba\u5b9a\u30c7\u30fc\u30bf\uff09\n  2. block \u3092\u30ad\u30e3\u30f3\u30d0\u30b9\u306b\u63cf\u753b\n  3. \u30c9\u30e9\u30c3\u30b0\u4e2d\u306a\u3089\u3001\u56f3\u5f62\u306e\u30c9\u30c3\u30c8\u5217\u3092 painter \u3067\u4e0a\u66f8\u304d\u63cf\u753b\uff08\u30d7\u30ec\u30d3\u30e5\u30fc\uff09\n  4. \u30dc\u30bf\u30f3\u304c\u96e2\u3055\u308c\u305f\u3089 ApplyLine \u3067\u78ba\u5b9a\u66f8\u304d\u8fbc\u307f<\/pre>\n<p>\u5927\u4e8b\u306a\u306e\u306f\u3001<strong>\u30c9\u30e9\u30c3\u30b0\u4e2d\u306f CHR \u30c7\u30fc\u30bf\u3092\u4e00\u5207\u89e6\u3089\u306a\u3044<\/strong>\u3053\u3068\u3067\u3059\u3002\u30d7\u30ec\u30d3\u30e5\u30fc\u306f\u3042\u304f\u307e\u3067 <code>painter<\/code> \u3067\u753b\u9762\u306b\u63cf\u3044\u3066\u3044\u308b\u3060\u3051\u3002egui \u306f\u5373\u6642\u30e2\u30fc\u30c9\u306a\u306e\u3067\u300c<strong>\u6bce\u30d5\u30ec\u30fc\u30e0\u4e0a\u304b\u3089\u63cf\u304f\u3060\u3051<\/strong>\u300d\u3067\u30d7\u30ec\u30d3\u30e5\u30fc\u304c\u5b9f\u73fe\u3067\u304d\u3066\u3001CHR \u306b\u3082\u30a2\u30f3\u30c9\u30a5\u30b9\u30bf\u30c3\u30af\u306b\u3082\u4f55\u306e\u5f71\u97ff\u3082\u4e0e\u3048\u307e\u305b\u3093\u3002<\/p>\n<p>\u30c9\u30e9\u30c3\u30b0\u958b\u59cb\u3067\u30d6\u30ed\u30c3\u30af\u5185\u306e\u8d77\u70b9\u5ea7\u6a19\u3092\u8a18\u9332\u3057\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/\/ \u7dda\u30c4\u30fc\u30eb\u306e\u30c9\u30e9\u30c3\u30b0\u8d77\u70b9\uff08\u30d6\u30ed\u30c3\u30af\u5185\u30c9\u30c3\u30c8\u5ea7\u6a19\uff09\npub(super) line_start_dot: Option&lt;(usize, usize)&gt;,<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">if matches!(self.drawing_tool, 2..=7) {\n    if response.drag_started_by(egui::PointerButton::Primary) {\n        self.line_start_dot = Some((px, py));\n        return None;\n    }\n    if response.dragged_by(egui::PointerButton::Primary) {\n        return None; \/\/ \u30d7\u30ec\u30d3\u30e5\u30fc\u306f\u4e0a\u3067\u63cf\u753b\u6e08\u307f\n    }\n    \/\/ \u30af\u30ea\u30c3\u30af\uff08\u30c9\u30e9\u30c3\u30b0\u306a\u3057\uff09: 1 \u70b9\u3068\u3057\u3066\u78ba\u5b9a\n    if response.clicked_by(egui::PointerButton::Primary) {\n        let pixels = vec![(tile_offset, dot_px, dot_py)];\n        return Some(EditorAction::ApplyLine { pixels });\n    }\n    return None;\n}<\/pre>\n<h5>\u56f3\u5f62\u306e\u7a2e\u985e\u306f shape_dots() \u3067\u632f\u308a\u5206\u3051\u308b<\/h5>\n<p>\u300c<strong>\u8d77\u70b9\u3068\u73fe\u5728\u4f4d\u7f6e\u304b\u3089\u30c9\u30c3\u30c8\u5ea7\u6a19\u306e\u30ea\u30b9\u30c8\u3092\u4f5c\u308b<\/strong>\u300d\u90e8\u5206\u306f\u3001\u30c4\u30fc\u30eb\u7a2e\u5225\u3067\u632f\u308a\u5206\u3051\u308b\u3060\u3051\u306e\u5c0f\u3055\u306a\u30c7\u30a3\u30b9\u30d1\u30c3\u30c1\u95a2\u6570\u306b\u307e\u3068\u3081\u3066\u3042\u308a\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/\/ \u30c4\u30fc\u30eb\u7a2e\u5225\u304b\u3089\u30c9\u30c3\u30c8\u5ea7\u6a19\u5217\u3092\u751f\u6210\uff08\u7dda\u30fb\u77e9\u5f62\u30fb\u6955\u5186\u5171\u901a\uff09\nfn shape_dots(sx: usize, sy: usize, ex: usize, ey: usize, tool: usize) -&gt; Vec&lt;(usize, usize)&gt; {\n    match tool {\n        2 =&gt; bresenham(sx, sy, ex, ey),\n        3 | 4 | 5 =&gt; rect_dots(sx, sy, ex, ey, tool),\n        6 =&gt; ellipse_dots(sx, sy, ex, ey, false),\n        7 =&gt; ellipse_dots(sx, sy, ex, ey, true),\n        _ =&gt; vec![],\n    }\n}<\/pre>\n<p>\u30d7\u30ec\u30d3\u30e5\u30fc\u63cf\u753b\u3082\u3001\u30ea\u30ea\u30fc\u30b9\u6642\u306e\u78ba\u5b9a\u3082\u3001<strong>\u3069\u3061\u3089\u3082\u540c\u3058 <code>shape_dots()<\/code> \u3092\u901a\u308b<\/strong>\u306e\u3067\u3001\u300c\u30d7\u30ec\u30d3\u30e5\u30fc\u3068\u78ba\u5b9a\u7d50\u679c\u304c\u5fae\u5999\u306b\u9055\u3046\u300d\u3068\u3044\u3046\u4e8b\u6545\u304c\u8d77\u304d\u307e\u305b\u3093\u3002<\/p>\n<h5>\u30d7\u30ec\u30d3\u30e5\u30fc<\/h5>\n<p>\u30c9\u30e9\u30c3\u30b0\u4e2d\u306f\u3053\u3046\u63cf\u3044\u3066\u3044\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">if matches!(self.drawing_tool, 2..=7) {\n    if let Some((sx, sy)) = self.line_start_dot {\n        let cur = response.interact_pointer_pos().or_else(|| response.hover_pos());\n        if let Some(p) = cur {\n            let rx = p.x - rect.left();\n            let ry = p.y - rect.top();\n            if rx &gt;= 0.0 &amp;&amp; ry &gt;= 0.0 {\n                let cx = ((rx \/ dot_size) as usize).min(block_px.saturating_sub(1));\n                let cy = ((ry \/ dot_size) as usize).min(block_px.saturating_sub(1));\n                let preview_color = self.dat_palette.color32(\n                    self.selected_palette_set,\n                    self.drawing_color_idx as usize,\n                    &amp;self.master_palette,\n                );\n                for (dx, dy) in shape_dots(sx, sy, cx, cy, self.drawing_tool) {\n                    if dx &gt;= block_px || dy &gt;= block_px { continue; }\n                    let dot_rect = egui::Rect::from_min_size(\n                        egui::pos2(rect.left() + dx as f32 * dot_size, rect.top() + dy as f32 * dot_size),\n                        egui::vec2(dot_size, dot_size),\n                    );\n                    painter.rect_filled(dot_rect, 0.0, preview_color);\n                }\n            }\n        }\n    }\n}<\/pre>\n<p>\u73fe\u5728\u4f4d\u7f6e\u306f <code>.min(block_px - 1)<\/code> \u3067\u30af\u30e9\u30f3\u30d7\u3057\u3066\u3044\u308b\u306e\u3067\u3001\u30ad\u30e3\u30f3\u30d0\u30b9\u306e\u5916\u306b\u30c9\u30e9\u30c3\u30b0\u3057\u3066\u3082\u56f3\u5f62\u304c\u7aef\u3067\u6b62\u307e\u308a\u307e\u3059\u3002<\/p>\n<h5>\u30ea\u30ea\u30fc\u30b9\u691c\u51fa\u306e\u30cf\u30de\u308a\u3069\u3053\u308d<\/h5>\n<p>\u3053\u3053\u3001\u5730\u5473\u306b\u30cf\u30de\u308a\u307e\u3057\u305f\u3002<\/p>\n<p>egui \u306e <code>response.interact_pointer_pos()<\/code> \u306f\u300c<strong>\u3053\u306e\u30a6\u30a3\u30b8\u30a7\u30c3\u30c8\u3068\u30a4\u30f3\u30bf\u30e9\u30af\u30b7\u30e7\u30f3\u4e2d\u306e\u30dd\u30a4\u30f3\u30bf\u4f4d\u7f6e<\/strong>\u300d\u3092\u8fd4\u3059\u306e\u3067\u3059\u304c\u3001<strong>\u30dc\u30bf\u30f3\u3092\u96e2\u3057\u305f\u77ac\u9593\u306e\u30d5\u30ec\u30fc\u30e0\u3067\u306f <code>None<\/code> \u306b\u306a\u308b\u3053\u3068\u304c\u3042\u308b<\/strong>\u3093\u3067\u3059\u3002\u306a\u306e\u3067\u300c\u96e2\u3057\u305f\u77ac\u9593\u306e\u5ea7\u6a19\u300d\u3092 <code>interact_pointer_pos()<\/code> \u3067\u53d6\u308d\u3046\u3068\u3059\u308b\u3068\u3001\u7d42\u70b9\u304c\u53d6\u308c\u305a\u306b\u56f3\u5f62\u304c\u78ba\u5b9a\u3067\u304d\u306a\u3044\u3001\u3068\u3044\u3046\u3053\u3068\u304c\u8d77\u304d\u307e\u3059\u3002<\/p>\n<p>\u5bfe\u7b56\u3068\u3057\u3066\u3001\u30ea\u30ea\u30fc\u30b9\u691c\u51fa\u306f <code>interact_pointer_pos()<\/code> \u3092\u898b\u308b\u524d\u306b <code>ctx.input()<\/code> \u3067\u76f4\u63a5\u30dc\u30bf\u30f3\u30ea\u30ea\u30fc\u30b9\u3092\u62fe\u3044\u3001\u7d42\u70b9\u306f <code>hover_pos()<\/code> \u304b\u3089\u53d6\u308b\u3088\u3046\u306b\u3057\u307e\u3057\u305f\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/ \u2500\u2500 \u7dda\u30fb\u77e9\u5f62\u30c4\u30fc\u30eb: \u30c9\u30e9\u30c3\u30b0\u7d42\u4e86\u691c\u51fa\uff08tool=2-5\uff09\nif matches!(self.drawing_tool, 2..=7) &amp;&amp; self.line_start_dot.is_some() {\n    let just_released = ui.ctx().input(|i| i.pointer.button_released(egui::PointerButton::Primary));\n    if just_released {\n        let end = ui.ctx().input(|i| i.pointer.hover_pos());\n        let top_col = top_left_tile % 16;\n        let top_row = top_left_tile \/ 16;\n        let (sx, sy) = self.line_start_dot.take().unwrap();\n        let (ex, ey) = end.and_then(|p| {\n            let rx = p.x - rect.left();\n            let ry = p.y - rect.top();\n            (rx &gt;= 0.0 &amp;&amp; ry &gt;= 0.0).then(|| {\n                let ex = ((rx \/ dot_size) as usize).min(block_px.saturating_sub(1));\n                let ey = ((ry \/ dot_size) as usize).min(block_px.saturating_sub(1));\n                (ex, ey)\n            })\n        }).unwrap_or((sx, sy));\n        let tool = self.drawing_tool;\n        let pixels = shape_dots(sx, sy, ex, ey, tool)\n            .into_iter()\n            .filter_map(|(dx, dy)| {\n                if dx &gt;= block_px || dy &gt;= block_px { return None; }\n                let off = ((top_row + dy \/ 8) * 16 + (top_col + dx \/ 8)) * 16;\n                (off + 16 &lt;= chr_len).then_some((off, dx % 8, dy % 8))\n            })\n            .collect();\n        return Some(EditorAction::ApplyLine { pixels });\n    }\n}<\/pre>\n<p>\u30d6\u30ed\u30c3\u30af\u5185\u306e\u30c9\u30c3\u30c8\u5ea7\u6a19 <code>(dx, dy)<\/code> \u3092\u300c\u30bf\u30a4\u30eb\u30aa\u30d5\u30bb\u30c3\u30c8 + \u30bf\u30a4\u30eb\u5185\u5ea7\u6a19\u300d\u306e 3 \u3064\u7d44\u306b\u5909\u63db\u3057\u3066 <code>ApplyLine<\/code> \u306b\u8a70\u3081\u3066\u3044\u307e\u3059\u3002\u3053\u306e 3 \u3064\u7d44\u306f\u524d\u56de\u306e\u30da\u30f3\u3068\u540c\u3058\u5f62\u5f0f\u306a\u306e\u3067\u3001<code>apply_action()<\/code> \u5074\u306f\u4f55\u3082\u7279\u5225\u6271\u3044\u3057\u307e\u305b\u3093\u3002<\/p>\n<h4>\u76f4\u7dda\uff1aBresenham \u306e\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0<\/h4>\n<p>\u76f4\u7dda\u306f\u30c9\u5b9a\u756a\u306e <strong>Bresenham<\/strong> \u3067\u3059\u3002\u6574\u6570\u6f14\u7b97\u3060\u3051\u3067\u3001\u59cb\u70b9\u304b\u3089\u7d42\u70b9\u307e\u3067\u9014\u5207\u308c\u306a\u304f 1 \u30c9\u30c3\u30c8\u5e45\u306e\u7dda\u3092\u5f15\u3051\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/\/ Bresenham \u306e\u76f4\u7dda\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\uff08\u30c9\u30c3\u30c8\u5ea7\u6a19\u30ea\u30b9\u30c8\u3092\u8fd4\u3059\uff09\nfn bresenham(x0: usize, y0: usize, x1: usize, y1: usize) -&gt; Vec&lt;(usize, usize)&gt; {\n    let (mut x, mut y) = (x0 as i32, y0 as i32);\n    let (x1, y1) = (x1 as i32, y1 as i32);\n    let dx = (x1 - x).abs();\n    let dy = -(y1 - y).abs();\n    let sx: i32 = if x &lt; x1 { 1 } else { -1 };\n    let sy: i32 = if y &lt; y1 { 1 } else { -1 };\n    let mut err = dx + dy;\n    let mut pts = Vec::new();\n    loop {\n        pts.push((x as usize, y as usize));\n        if x == x1 &amp;&amp; y == y1 { break; }\n        let e2 = 2 * err;\n        if e2 &gt;= dy { err += dy; x += sx; }\n        if e2 &lt;= dx { err += dx; y += sy; }\n    }\n    pts\n}<\/pre>\n<p>\u300c\u8aa4\u5dee <code>err<\/code> \u3092\u7a4d\u307f\u4e0a\u3052\u3066\u3044\u3063\u3066\u3001\u95be\u5024\u3092\u8d85\u3048\u305f\u3089\u8ef8\u65b9\u5411\u306b 1 \u6b69\u9032\u3081\u308b\u300d\u3068\u3044\u3046\u53e4\u5178\u7684\u306a\u3084\u3064\u3067\u3059\u306d\u3002<code>dy<\/code> \u3092\u8ca0\u306b\u3057\u3066\u304a\u3044\u3066 <code>err = dx + dy<\/code> \u304b\u3089\u59cb\u3081\u308b\u3001Wikipedia \u306b\u8f09\u3063\u3066\u3044\u308b\u5168\u65b9\u5411\u5bfe\u5fdc\u7248\u305d\u306e\u307e\u307e\u3067\u3059\u3002\u6d6e\u52d5\u5c0f\u6570\u70b9\u3092\u4f7f\u308f\u306a\u3044\u306e\u3067\u3001\u3069\u306e\u89d2\u5ea6\u3067\u3082\u540c\u3058\u5165\u529b\u306a\u3089\u5fc5\u305a\u540c\u3058\u30c9\u30c3\u30c8\u5217\u306b\u306a\u308a\u307e\u3059\u3002\u30c9\u30c3\u30c8\u7d75\u3067\u306f\u300c\u518d\u73fe\u6027\u300d\u304c\u7d50\u69cb\u5927\u4e8b\u3067\u3057\u3066\u3002<\/p>\n<h4>\u77e9\u5f62\uff1a\u67a0\u7dda \/ \u5857\u308a \/ \u30d1\u30bf\u30fc\u30f3<\/h4>\n<p>\u77e9\u5f62\u306f 3 \u7a2e\u985e\u3042\u308a\u307e\u3059\u304c\u30011 \u3064\u306e\u95a2\u6570\u3067 <code>kind<\/code> \u3092\u5207\u308a\u66ff\u3048\u3066\u3044\u308b\u3060\u3051\u3067\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/\/ \u77e9\u5f62\u30c9\u30c3\u30c8\u751f\u6210\uff08kind: 3=\u67a0\u7dda, 4=\u5857\u308a, 5=\u30d1\u30bf\u30fc\u30f3\uff09\nfn rect_dots(sx: usize, sy: usize, ex: usize, ey: usize, kind: usize) -&gt; Vec&lt;(usize, usize)&gt; {\n    let (x0, x1) = (sx.min(ex), sx.max(ex));\n    let (y0, y1) = (sy.min(ey), sy.max(ey));\n    let parity = (sx + sy) % 2;\n    let mut pts = Vec::new();\n    for y in y0..=y1 {\n        for x in x0..=x1 {\n            let draw = match kind {\n                3 =&gt; x == x0 || x == x1 || y == y0 || y == y1,\n                4 =&gt; true,\n                5 =&gt; (x + y) % 2 == parity,\n                _ =&gt; false,\n            };\n            if draw { pts.push((x, y)); }\n        }\n    }\n    pts\n}<\/pre>\n<ul>\n<li>\u67a0\u7dda\uff1a\u4e0a\u4e0b\u5de6\u53f3\u3044\u305a\u308c\u304b\u306e\u8fba\u4e0a\u306b\u3042\u308b\u30c9\u30c3\u30c8\u3060\u3051<\/li>\n<li>\u5857\u308a\uff1a\u5168\u90e8<\/li>\n<li>\u30d1\u30bf\u30fc\u30f3\uff1a<code>(x + y) % 2<\/code> \u304c\u8d77\u70b9\u306e\u30d1\u30ea\u30c6\u30a3\u3068\u4e00\u81f4\u3059\u308b\u30c9\u30c3\u30c8\u3060\u3051<\/li>\n<\/ul>\n<p>\u30d1\u30bf\u30fc\u30f3\u77e9\u5f62\u306e\u30d1\u30ea\u30c6\u30a3\u3092<strong>\u8d77\u70b9 <code>(sx, sy)<\/code> \u57fa\u6e96<\/strong>\u306b\u3057\u3066\u3044\u308b\u306e\u304c\u30dd\u30a4\u30f3\u30c8\u3067\u3001\u3053\u3046\u3057\u3066\u304a\u304f\u3068\u30c9\u30e9\u30c3\u30b0\u3092\u3069\u3061\u3089\u306e\u65b9\u5411\u306b\u4f38\u3070\u3057\u3066\u3082\u3001\u8d77\u70b9\u306e\u30c9\u30c3\u30c8\u306f\u5fc5\u305a\u5857\u3089\u308c\u307e\u3059\u3002\u300c<strong>\u30af\u30ea\u30c3\u30af\u3057\u305f\u5834\u6240\u304b\u3089\u6a21\u69d8\u304c\u59cb\u307e\u308b<\/strong>\u300d\u307b\u3046\u304c\u76f4\u611f\u306b\u5408\u3046\u306e\u3067\u3002<\/p>\n<h4>\u6955\u5186\uff1a\u30d0\u30a6\u30f3\u30c7\u30a3\u30f3\u30b0\u30dc\u30c3\u30af\u30b9\u304b\u3089\u6c42\u3081\u308b<\/h4>\n<p>\u6955\u5186\u306f\u3001\u30c9\u30e9\u30c3\u30b0\u306e\u5bfe\u89d2 2 \u70b9\u3092\u30d0\u30a6\u30f3\u30c7\u30a3\u30f3\u30b0\u30dc\u30c3\u30af\u30b9\u3068\u3057\u3066\u3001\u305d\u306e\u5185\u63a5\u6955\u5186\u3092\u63cf\u304d\u307e\u3059\u3002<\/p>\n<p>\u76f4\u7dda\u3068\u9055\u3063\u3066\u3001\u3053\u3061\u3089\u306f\u6d6e\u52d5\u5c0f\u6570\u70b9\u3067\u7d20\u76f4\u306b\u6955\u5186\u306e\u5f0f <code>(x\u2212cx)\u00b2\/rx\u00b2 + (y\u2212cy)\u00b2\/ry\u00b2 \u2264 1<\/code> \u3092\u4f7f\u3063\u3066\u3044\u307e\u3059\u3002\u4e2d\u70b9\u6955\u5186\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\u306e\u3088\u3046\u306a\u6574\u6570\u7248\u3082\u3042\u308b\u306e\u3067\u3059\u304c\u3001\u30ad\u30e3\u30f3\u30d0\u30b9\u304c\u6700\u5927 128\u00d7128 \u30c9\u30c3\u30c8\u306a\u306e\u3067\u3001\u7d20\u76f4\u306b\u8a08\u7b97\u3057\u3066\u3082\u5168\u7136\u554f\u984c\u306a\u3044\u901f\u5ea6\u3067\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/\/ \u6955\u5186\u30c9\u30c3\u30c8\u751f\u6210\uff08fill=false: \u8f2a\u90ed\u306e\u307f \/ fill=true: \u5185\u90e8\u5857\u308a\uff09\nfn ellipse_dots(sx: usize, sy: usize, ex: usize, ey: usize, fill: bool) -&gt; Vec&lt;(usize, usize)&gt; {\n    let (x0, x1) = (sx.min(ex) as i32, sx.max(ex) as i32);\n    let (y0, y1) = (sy.min(ey) as i32, sy.max(ey) as i32);\n    let cx = (x0 + x1) as f64 \/ 2.0;\n    let cy = (y0 + y1) as f64 \/ 2.0;\n    let rx = (x1 - x0) as f64 \/ 2.0;\n    let ry = (y1 - y0) as f64 \/ 2.0;\n    let rx2 = rx * rx;\n    let ry2 = ry * ry;\n    let mut set = std::collections::HashSet::new();\n\n    if fill {\n        \/\/ \u5404\u884c\u306e\u6955\u5186\u5185\u30b9\u30ad\u30e3\u30f3\u30e9\u30a4\u30f3\n        for y in y0..=y1 {\n            let dy = y as f64 - cy;\n            let t = if ry &gt; 0.0 { 1.0 - dy * dy \/ ry2 } else { if dy.abs() &lt; 0.5 { 1.0 } else { -1.0 } };\n            if t &lt; 0.0 { continue; }\n            let hw = if rx &gt; 0.0 { (rx2 * t).sqrt() } else { 0.0 };\n            let xl = (cx - hw).ceil() as i32;\n            let xr = (cx + hw).floor() as i32;\n            for x in xl.max(x0)..=xr.min(x1) {\n                set.insert((x as usize, y as usize));\n            }\n        }\n    } else {\n        \/\/ \u5404\u884c\u306e\u5de6\u53f3\u7aef\u70b9\n        for y in y0..=y1 {\n            let dy = y as f64 - cy;\n            let t = if ry &gt; 0.0 { 1.0 - dy * dy \/ ry2 } else { if dy.abs() &lt; 0.5 { 1.0 } else { -1.0 } };\n            if t &lt; 0.0 { continue; }\n            let hw = if rx &gt; 0.0 { (rx2 * t).sqrt() } else { 0.0 };\n            let xl = (cx - hw).round() as i32;\n            let xr = (cx + hw).round() as i32;\n            if (x0..=x1).contains(&amp;xl) { set.insert((xl as usize, y as usize)); }\n            if (x0..=x1).contains(&amp;xr) { set.insert((xr as usize, y as usize)); }\n        }\n        \/\/ \u5404\u5217\u306e\u4e0a\u4e0b\u7aef\u70b9\uff08\u9699\u9593\u3092\u57cb\u3081\u308b\uff09\n        for x in x0..=x1 {\n            let dx = x as f64 - cx;\n            let t = if rx &gt; 0.0 { 1.0 - dx * dx \/ rx2 } else { if dx.abs() &lt; 0.5 { 1.0 } else { -1.0 } };\n            if t &lt; 0.0 { continue; }\n            let hh = if ry &gt; 0.0 { (ry2 * t).sqrt() } else { 0.0 };\n            let yt = (cy - hh).round() as i32;\n            let yb = (cy + hh).round() as i32;\n            if (y0..=y1).contains(&amp;yt) { set.insert((x as usize, yt as usize)); }\n            if (y0..=y1).contains(&amp;yb) { set.insert((x as usize, yb as usize)); }\n        }\n    }\n    set.into_iter().collect()\n}<\/pre>\n<h5>\u5857\u308a\uff1a\u30b9\u30ad\u30e3\u30f3\u30e9\u30a4\u30f3<\/h5>\n<p>\u5857\u308a\u306f\u5404\u884c <code>y<\/code> \u306b\u3064\u3044\u3066\u3001\u6955\u5186\u306e\u5f0f\u3092 <code>x<\/code> \u306b\u3064\u3044\u3066\u89e3\u3044\u305f\u534a\u5e45 <code>hw = rx \u00b7 \u221a(1 \u2212 dy\u00b2\/ry\u00b2)<\/code> \u3092\u6c42\u3081\u3001<code>cx \u00b1 hw<\/code> \u306e\u7bc4\u56f2\u3092\u5857\u308b\u3060\u3051\u3002\u5178\u578b\u7684\u306a\u30b9\u30ad\u30e3\u30f3\u30e9\u30a4\u30f3\u6cd5\u3067\u3059\u3002<\/p>\n<h5>\u8f2a\u90ed\uff1a\u884c\u306e\u7aef\u70b9 + \u5217\u306e\u7aef\u70b9<\/h5>\n<p>\u8f2a\u90ed\u306e\u307b\u3046\u304c\u5c11\u3057\u5de5\u592b\u304c\u8981\u308a\u307e\u3059\u3002<\/p>\n<p>\u5404\u884c\u306e\u5de6\u53f3\u7aef\u70b9\u3060\u3051\u3092\u6253\u3063\u3066\u3044\u304f\u3068\u3001\u6955\u5186\u306e\u4e0a\u4e0b\uff08\u50be\u304d\u304c\u6025\u306a\u90e8\u5206\uff09\u3067<strong>\u9699\u9593\u304c\u7a7a\u304f<\/strong>\u3093\u3067\u3059\u3002\u884c\u3054\u3068\u306b 1 \u30c9\u30c3\u30c8\u305a\u3064\u3057\u304b\u9032\u307e\u306a\u3044\u306e\u306b\u3001x \u65b9\u5411\u306b\u306f\u4e00\u6c17\u306b\u4f55\u30c9\u30c3\u30c8\u3082\u52d5\u304f\u306e\u3067\u3002<\/p>\n<p>\u305d\u3053\u3067\u3001<strong>\u5404\u884c\u306e\u5de6\u53f3\u7aef\u70b9\u306b\u52a0\u3048\u3066\u3001\u5404\u5217\u306e\u4e0a\u4e0b\u7aef\u70b9\u3082\u6253\u3064<\/strong>\u3088\u3046\u306b\u3057\u307e\u3057\u305f\u3002\u884c\u65b9\u5411\u3067\u9699\u9593\u304c\u7a7a\u304f\u5834\u6240\u306f\u5217\u65b9\u5411\u3067\u57cb\u307e\u308a\u3001\u5217\u65b9\u5411\u3067\u9699\u9593\u304c\u7a7a\u304f\u5834\u6240\u306f\u884c\u65b9\u5411\u3067\u57cb\u307e\u308b\u3001\u3068\u3044\u3046\u95a2\u4fc2\u3067\u3059\u3002\u4e21\u65b9\u6253\u3064\u3068\u91cd\u8907\u3059\u308b\u30c9\u30c3\u30c8\u304c\u51fa\u308b\u306e\u3067 <code>HashSet<\/code> \u3067\u9664\u53bb\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<p><code>ry &gt; 0.0<\/code> \u306e\u5206\u5c90\u306f\u3001\u9ad8\u3055 0\uff08\u4e00\u76f4\u7dda\u306b\u30c9\u30e9\u30c3\u30b0\u3057\u305f\u3068\u304d\uff09\u306e\u30bc\u30ed\u9664\u7b97\u907f\u3051\u3067\u3059\u3002\u3053\u306e\u5834\u5408\u306f <code>dy.abs() &lt; 0.5<\/code> \u306e\u884c\u3060\u3051\u3001\u3064\u307e\u308a\u6a2a\u4e00\u7dda\u3068\u3057\u3066\u63cf\u304b\u308c\u307e\u3059\u3002<\/p>\n<p>\u6570\u30c9\u30c3\u30c8\u3057\u304b\u306a\u3044\u5c0f\u3055\u306a\u6955\u5186\u3060\u3068\u3001\u3055\u3059\u304c\u306b\u300c\u4e38\u300d\u3068\u3044\u3046\u3088\u308a\u300c\u306a\u3093\u3068\u306a\u304f\u4e38\u3063\u307d\u3044\u4f55\u304b\u300d\u306b\u306a\u308a\u307e\u3059\u304c\u30018\u00d78 \u306e\u30b9\u30d7\u30e9\u30a4\u30c8\u3067\u4f7f\u3046\u5206\u306b\u306f\u307e\u3041\u5341\u5206\u304b\u306a\u3068\u3002<\/p>\n<h4>\u5857\u308a\u3064\u3076\u3057\uff1aBFS \u306e\u30d5\u30e9\u30c3\u30c9\u30d5\u30a3\u30eb<\/h4>\n<p>\u5857\u308a\u3064\u3076\u3057\u306f\u3001\u30af\u30ea\u30c3\u30af\u3057\u305f\u30c9\u30c3\u30c8\u3068\u540c\u3058\u8272\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3067\u96a3\u63a5\u3057\u3066\u3044\u308b\u9818\u57df\u3092\u3001\u63cf\u753b\u8272\u3067\u5857\u308a\u307e\u3059\u3002<strong>\u5e45\u512a\u5148\u63a2\u7d22\uff08BFS\uff09<\/strong> \u3067\u3001\u4e0a\u4e0b\u5de6\u53f3\u306e 4 \u65b9\u5411\u9023\u7d50\u3067\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/\/ \u5857\u308a\u3064\u3076\u3057: \u30af\u30ea\u30c3\u30af\u70b9\u304b\u3089\u540c\u8272\u306e\u96a3\u63a5\u30c9\u30c3\u30c8\u3092 BFS \u3067\u53ce\u96c6\nfn flood_fill_dots(\n    block: &amp;[Vec],\n    sx: usize, sy: usize,\n    block_px: usize,\n    top_row: usize, top_col: usize,\n    fill_color: u8, chr_len: usize,\n) -&gt; Vec&lt;(usize, usize, usize)&gt; {\n    let target = block[sy][sx];\n    if target == fill_color { return vec![]; }\n    let mut visited = vec![vec![false; block_px]; block_px];\n    let mut queue = std::collections::VecDeque::new();\n    queue.push_back((sx, sy));\n    visited[sy][sx] = true;\n    let mut pixels = Vec::new();\n    while let Some((x, y)) = queue.pop_front() {\n        let off = ((top_row + y \/ 8) * 16 + (top_col + x \/ 8)) * 16;\n        if off + 16 &lt;= chr_len {\n            pixels.push((off, x % 8, y % 8));\n        }\n        for (nx, ny) in [\n            (x + 1, y), (x.wrapping_sub(1), y),\n            (x, y + 1), (x, y.wrapping_sub(1)),\n        ] {\n            if nx &lt; block_px &amp;&amp; ny &lt; block_px &amp;&amp; !visited[ny][nx] &amp;&amp; block[ny][nx] == target {\n                visited[ny][nx] = true;\n                queue.push_back((nx, ny));\n            }\n        }\n    }\n    pixels\n}<\/pre>\n<p>\u3044\u304f\u3064\u304b\u30dd\u30a4\u30f3\u30c8\u3092\u3002<\/p>\n<ul>\n<li>\u6bd4\u8f03\u3059\u308b\u306e\u306f RGB \u3067\u306f\u306a\u304f<strong>\u30d1\u30ec\u30c3\u30c8\u306e\u8272\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\uff080\u301c3\uff09<\/strong>\u3067\u3059\u3002CHR \u306b\u5165\u3063\u3066\u3044\u308b\u306e\u306f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306a\u306e\u3067\u3001\u3053\u308c\u304c\u6b63\u3057\u3044<\/li>\n<li>\u63a2\u7d22\u5bfe\u8c61\u306f<strong>\u30c7\u30b3\u30fc\u30c9\u6e08\u307f\u306e <code>block<\/code><\/strong>\u306a\u306e\u3067\u3001\u63a2\u7d22\u4e2d\u306b CHR \u3092\u518d\u30d1\u30fc\u30b9\u3057\u307e\u305b\u3093<\/li>\n<li><code>target == fill_color<\/code> \u306a\u3089\u4f55\u3082\u3057\u306a\u3044\u3002\u540c\u3058\u8272\u3067\u5857\u308d\u3046\u3068\u3057\u3066\u7121\u9650\u30eb\u30fc\u30d7\u3001\u3092\u9632\u3050\u5b9a\u756a\u306e\u30ac\u30fc\u30c9<\/li>\n<li><code>x.wrapping_sub(1)<\/code> \u306f <code>usize<\/code> \u306e 0 \u2212 1 \u3067 panic \u3057\u306a\u3044\u3088\u3046\u306b\u3059\u308b\u5c0f\u6280\u3067\u3001\u30e9\u30c3\u30d7\u3057\u3066\u5de8\u5927\u306a\u5024\u306b\u306a\u3063\u3066\u3082 <code>nx &lt; block_px<\/code> \u3067\u5f3e\u304b\u308c\u307e\u3059<\/li>\n<li>\u7d50\u679c\u306f <code>(\u30aa\u30d5\u30bb\u30c3\u30c8, px, py)<\/code> \u306e 3 \u3064\u7d44\u306e\u30ea\u30b9\u30c8\u306a\u306e\u3067\u3001\u305d\u306e\u307e\u307e <code>ApplyLine<\/code> \u306b\u6d41\u305b\u307e\u3059<\/li>\n<\/ul>\n<p>\u5857\u308a\u3064\u3076\u3057\u306e\u7bc4\u56f2\u306f<strong>\u73fe\u5728\u8868\u793a\u4e2d\u306e\u30d5\u30a9\u30fc\u30ab\u30b9\u30d6\u30ed\u30c3\u30af\u5185<\/strong>\u306b\u9650\u5b9a\u3055\u308c\u307e\u3059\u3002\u30d5\u30a9\u30fc\u30ab\u30b9 8px \u306a\u3089 1 \u30bf\u30a4\u30eb\u5185\u3001128px \u306a\u3089 16\u00d716 \u30bf\u30a4\u30eb\u306e\u7bc4\u56f2\u3002CHR \u5168\u4f53\u306b\u5e83\u304c\u3063\u305f\u308a\u306f\u3057\u306a\u3044\u306e\u3067\u3001\u5b89\u5fc3\u3057\u3066\u4f7f\u3048\u307e\u3059\u3002<\/p>\n<h5>apply_line\uff1a\u5168\u56f3\u5f62\u30c4\u30fc\u30eb\u5171\u901a\u306e\u66f8\u304d\u8fbc\u307f<\/h5>\n<p>\u76f4\u7dda\u30fb\u77e9\u5f62\u30fb\u6955\u5186\u30fb\u5857\u308a\u3064\u3076\u3057\u306f\u5168\u90e8 <code>ApplyLine { pixels }<\/code> \u3068\u3057\u3066 <code>apply_action()<\/code> \u306b\u5c4a\u304d\u3001<code>apply_line()<\/code> \u3067\u51e6\u7406\u3055\u308c\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">pub(super) fn apply_line(&amp;mut self, pixels: Vec&lt;(usize, usize, usize)&gt;) {\n    if pixels.is_empty() { return; }\n    let chr_len = match &amp;self.rom {\n        Some(r) =&gt; r.chr_data().len(),\n        None =&gt; return,\n    };\n    \/\/ undo \u30d0\u30c3\u30c1: \u5f71\u97ff\u30bf\u30a4\u30eb\u3092\u91cd\u8907\u306a\u304f\u4fdd\u5b58\n    let mut seen = std::collections::HashSet::new();\n    let mut batch: Vec&lt;(usize, [u8; 16])&gt; = Vec::new();\n    for &amp;(off, _, _) in &amp;pixels {\n        if off + 16 &lt;= chr_len &amp;&amp; seen.insert(off) {\n            let saved: [u8; 16] = self.rom.as_ref().unwrap().chr_data()\n                [off..off + 16].try_into().unwrap();\n            batch.push((off, saved));\n        }\n    }\n    self.push_undo_batch(batch);\n    \/\/ \u30c9\u30c3\u30c8\u66f8\u304d\u8fbc\u307f\n    let color = self.drawing_color_idx;\n    for (off, px, py) in pixels {\n        if off + 16 &lt;= chr_len {\n            if let Some(rom) = &amp;mut self.rom {\n                encode_dot(&amp;mut rom.chr_data_mut()[off..off + 16], px, py, color);\n            }\n        }\n    }\n    self.is_modified = true;\n    self.texture_dirty = true;\n}<\/pre>\n<p>\u3084\u3063\u3066\u3044\u308b\u3053\u3068\u306f 2 \u6bb5\u968e\u3067\u3001\u307e\u305a\u5f71\u97ff\u3059\u308b\u30bf\u30a4\u30eb\u306e\u30aa\u30d5\u30bb\u30c3\u30c8\u3092 <code>HashSet<\/code> \u3067\u91cd\u8907\u9664\u53bb\u3057\u306a\u304c\u3089\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u53d6\u308a\u3001<code>push_undo_batch()<\/code> \u306b\u7a4d\u3080\u3002\u305d\u308c\u304b\u3089\u5404\u30c9\u30c3\u30c8\u3092 <code>encode_dot()<\/code> \u3067\u66f8\u304f\u3002<strong>\u66f8\u304f\u524d\u306b\u5168\u90e8\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u53d6\u308b<\/strong>\u306e\u304c\u91cd\u8981\u3067\u3001\u9806\u756a\u3092\u9006\u306b\u3059\u308b\u3068\u5857\u3063\u305f\u5f8c\u306e\u72b6\u614b\u3092\u4fdd\u5b58\u3057\u3066\u3057\u307e\u3044\u307e\u3059\u3002<\/p>\n<p>\u524d\u56de\u306e\u30da\u30f3\u3067\u306f\u300c\u30b9\u30c8\u30ed\u30fc\u30af\u4e2d\u306b\u521d\u3081\u3066\u89e6\u308c\u305f\u30bf\u30a4\u30eb\u300d\u3092\u8ffd\u8de1\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3057\u305f\u304c\u3001\u56f3\u5f62\u30c4\u30fc\u30eb\u306f\u30c9\u30c3\u30c8\u5217\u304c\u4e00\u5ea6\u306b\u78ba\u5b9a\u3059\u308b\u306e\u3067\u3001\u3053\u3061\u3089\u306e\u307b\u3046\u304c\u30b7\u30f3\u30d7\u30eb\u3067\u3059\u306d\u3002<\/p>\n<h4>\u30b9\u30bf\u30f3\u30d7\uff1a2 \u30d5\u30a7\u30fc\u30ba\u306e\u30b3\u30d4\u30fc &amp; \u30da\u30fc\u30b9\u30c8<\/h4>\n<p>\u6700\u5f8c\u306f\u30b9\u30bf\u30f3\u30d7\u30c4\u30fc\u30eb\u3067\u3059\u3002\u3053\u308c\u3060\u3051\u4ed6\u3068\u306f\u6bdb\u8272\u304c\u9055\u3063\u3066\u3001<strong>2 \u6bb5\u968e\u306e\u72b6\u614b\u3092\u6301\u3064<\/strong>\u30c4\u30fc\u30eb\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n<table style=\"border-collapse: collapse; width: 100%;\">\n<thead>\n<tr>\n<th>\u30d5\u30a7\u30fc\u30ba<\/th>\n<th>\u64cd\u4f5c<\/th>\n<th>\u52d5\u4f5c<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Phase 1\uff08\u9078\u629e\uff09<\/td>\n<td>\u30c9\u30e9\u30c3\u30b0<\/td>\n<td>\u70b9\u7dda\u306e\u67a0\u3067\u7bc4\u56f2\u3092\u30d7\u30ec\u30d3\u30e5\u30fc<\/td>\n<\/tr>\n<tr>\n<td>\u00a0<\/td>\n<td>\u30ea\u30ea\u30fc\u30b9<\/td>\n<td>\u7bc4\u56f2\u3092\u78ba\u5b9a\u3057\u3001\u8272\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u30d0\u30c3\u30d5\u30a1\u306b\u30b3\u30d4\u30fc<\/td>\n<\/tr>\n<tr>\n<td>Phase 2\uff08\u8cbc\u308a\u4ed8\u3051\uff09<\/td>\n<td>\u30c9\u30e9\u30c3\u30b0<\/td>\n<td>\u70b9\u7dda\u306e\u67a0 + \u30c9\u30c3\u30c8\u306e\u30d7\u30ec\u30d3\u30e5\u30fc\u304c\u30ab\u30fc\u30bd\u30eb\u306b\u8ffd\u5f93<\/td>\n<\/tr>\n<tr>\n<td>\u00a0<\/td>\n<td>\u30ea\u30ea\u30fc\u30b9<\/td>\n<td>CHR \u306b\u66f8\u304d\u8fbc\u3080\uff08\u30d0\u30c3\u30d5\u30a1\u306f\u4fdd\u6301\uff09<\/td>\n<\/tr>\n<tr>\n<td>\u00a0<\/td>\n<td>\u53f3\u30af\u30ea\u30c3\u30af<\/td>\n<td>\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u3066 Phase 1 \u306b\u623b\u308b<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u30d0\u30c3\u30d5\u30a1\u304c\u4fdd\u6301\u3055\u308c\u308b\u306e\u3067\u3001\u540c\u3058\u7d75\u3092\u4f55\u5ea6\u3067\u3082\u30dd\u30f3\u30dd\u30f3\u62bc\u305b\u307e\u3059\u3002\u30b9\u30bf\u30f3\u30d7\u3001\u3068\u3044\u3046\u30cd\u30fc\u30df\u30f3\u30b0\u306f\u305d\u3053\u304b\u3089\u3068\u306a\u308a\u307e\u3059\u3002<\/p>\n<h5>\u72b6\u614b<\/h5>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/\/ \u30b9\u30bf\u30f3\u30d7 Phase1: \u9078\u629e\u30c9\u30e9\u30c3\u30b0\u8d77\u70b9\npub(super) stamp_sel_start: Option&lt;(usize, usize)&gt;,\n\/\/\/ \u30b9\u30bf\u30f3\u30d7 Phase2: \u78ba\u5b9a\u6e08\u307f (w, h, pixels[h][w]) \u30d0\u30c3\u30d5\u30a1\npub(super) stamp_buffer: Option&lt;(usize, usize, Vec&lt;vec&gt;)&gt;,\n\/\/\/ \u30b9\u30bf\u30f3\u30d7 Phase2: \u73fe\u5728\u306e\u8cbc\u308a\u4ed8\u3051\u4f4d\u7f6e\uff08\u30d6\u30ed\u30c3\u30af\u5de6\u4e0a\u30c9\u30c3\u30c8\u5ea7\u6a19\uff09\npub(super) stamp_paste_pos: (usize, usize),\n\/\/\/ \u30b9\u30bf\u30f3\u30d7 Phase2: \u30c9\u30e9\u30c3\u30b0\u4e2d\u306e\u30a2\u30f3\u30ab\u30fc\u30aa\u30d5\u30bb\u30c3\u30c8\uff08\u30c9\u30e9\u30c3\u30b0\u958b\u59cb\u70b9 - \u8cbc\u308a\u4ed8\u3051\u4f4d\u7f6e\uff09\npub(super) stamp_drag_anchor: Option&lt;(i32, i32)&gt;,&lt;\/vec<\/pre>\n<p>\u3053\u306e 4 \u3064\u306e\u7d44\u307f\u5408\u308f\u305b\u3067\u30d5\u30a7\u30fc\u30ba\u304c\u6c7a\u307e\u308a\u307e\u3059\u3002<\/p>\n<table style=\"border-collapse: collapse; width: 100%;\">\n<thead>\n<tr>\n<th>\u72b6\u614b<\/th>\n<th>\u6761\u4ef6<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u5f85\u6a5f<\/td>\n<td><code>buffer = None<\/code>, <code>sel_start = None<\/code><\/td>\n<\/tr>\n<tr>\n<td>Phase 1 \u9078\u629e\u4e2d<\/td>\n<td><code>sel_start = Some<\/code><\/td>\n<\/tr>\n<tr>\n<td>Phase 2 \u5f85\u6a5f<\/td>\n<td><code>buffer = Some<\/code>, <code>sel_start = None<\/code>, <code>anchor = None<\/code><\/td>\n<\/tr>\n<tr>\n<td>Phase 2 \u30c9\u30e9\u30c3\u30b0\u4e2d<\/td>\n<td><code>buffer = Some<\/code>, <code>sel_start = None<\/code>, <code>anchor = Some<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u5c02\u7528\u306e enum \u3092\u5207\u3063\u3066\u3082\u826f\u304b\u3063\u305f\u306e\u3067\u3059\u304c\u3001egui \u306e\u5373\u6642\u30e2\u30fc\u30c9\u3060\u3068\u300c\u3053\u306e\u6761\u4ef6\u306e\u3068\u304d\u306f\u3053\u3046\u63cf\u304f\u300d\u3092 <code>if<\/code> \u3067\u4e26\u3079\u305f\u307b\u3046\u304c\u8aad\u307f\u3084\u3059\u304b\u3063\u305f\u306e\u3067\u3001\u3053\u3046\u3044\u3046\u5f62\u306b\u843d\u3061\u7740\u3044\u3066\u3044\u307e\u3059\u3002<\/p>\n<h5>Phase 1\uff1a\u7bc4\u56f2\u3092\u30d0\u30c3\u30d5\u30a1\u306b\u53d6\u308a\u8fbc\u3080<\/h5>\n<p>\u30ea\u30ea\u30fc\u30b9\u6642\u306b\u3001\u30c7\u30b3\u30fc\u30c9\u6e08\u307f\u306e <code>block<\/code> \u304b\u3089\u7bc4\u56f2\u3092\u5207\u308a\u51fa\u3059\u3060\u3051\u3067\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">let (x0, x1) = (sx.min(ex), sx.max(ex));\nlet (y0, y1) = (sy.min(ey), sy.max(ey));\nlet w = x1 - x0 + 1;\nlet h = y1 - y0 + 1;\nlet pixels: Vec&lt;vec&gt; = (y0..=y1)\n    .map(|y| (x0..=x1).map(|x| block[y][x]).collect())\n    .collect();\nself.stamp_buffer = Some((w, h, pixels));\nself.stamp_paste_pos = (x0, y0);\nself.stamp_drag_anchor = None;&lt;\/vec<\/pre>\n<p>\u30d0\u30c3\u30d5\u30a1\u306b\u5165\u308b\u306e\u306f<strong>\u8272\u30a4\u30f3\u30c7\u30c3\u30af\u30b9<\/strong>\u306a\u306e\u3067\u3001\u8cbc\u308a\u4ed8\u3051\u5148\u3067\u30d1\u30ec\u30c3\u30c8\u30bb\u30c3\u30c8\u3092\u5909\u3048\u3066\u3082\u3001\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3068\u3057\u3066\u6b63\u3057\u304f\u89e3\u91c8\u3055\u308c\u307e\u3059\u3002\u524d\u56de\u306e\u30bf\u30a4\u30eb\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u304c CHR \u30d0\u30a4\u30c8\u5217\u3060\u3063\u305f\u306e\u3068\u540c\u3058\u8003\u3048\u65b9\u3067\u3059\u306d\u3002<\/p>\n<p>\u30c9\u30e9\u30c3\u30b0\u305b\u305a\u306b\u30af\u30ea\u30c3\u30af\u3060\u3051\u3057\u305f\u5834\u5408\u306f\u3001\u305d\u306e 1 \u30c9\u30c3\u30c8\u3092 1\u00d71 \u306e\u30b9\u30bf\u30f3\u30d7\u3068\u3057\u3066\u53d6\u308a\u8fbc\u307f\u307e\u3059\u3002<\/p>\n<h5>Phase 2\uff1a\u30a2\u30f3\u30ab\u30fc\u3067\u81ea\u7136\u306b\u52d5\u304b\u3059<\/h5>\n<p>\u8cbc\u308a\u4ed8\u3051\u4f4d\u7f6e\u3092\u30c9\u30e9\u30c3\u30b0\u3067\u52d5\u304b\u3059\u3068\u304d\u3001\u5358\u7d14\u306b\u300c\u30ab\u30fc\u30bd\u30eb\u4f4d\u7f6e = \u30b9\u30bf\u30f3\u30d7\u306e\u5de6\u4e0a\u300d\u306b\u3059\u308b\u3068\u3001\u63b4\u3093\u3060\u77ac\u9593\u306b\u30b9\u30bf\u30f3\u30d7\u304c\u30ab\u30fc\u30bd\u30eb\u3078\u30b9\u30ca\u30c3\u30d7\u3057\u3066\u98db\u3093\u3067\u3057\u307e\u3044\u307e\u3059\u3002<\/p>\n<p>\u305d\u3053\u3067\u3001\u30c9\u30e9\u30c3\u30b0\u958b\u59cb\u6642\u306b\u300c\u30ab\u30fc\u30bd\u30eb\u4f4d\u7f6e \u2212 \u73fe\u5728\u306e\u8cbc\u308a\u4ed8\u3051\u4f4d\u7f6e\u300d\u3092<strong>\u30a2\u30f3\u30ab\u30fc<\/strong>\u3068\u3057\u3066\u8a18\u9332\u3057\u3001\u30c9\u30e9\u30c3\u30b0\u4e2d\u306f\u30ab\u30fc\u30bd\u30eb\u4f4d\u7f6e\u304b\u3089\u30a2\u30f3\u30ab\u30fc\u3092\u5f15\u3044\u305f\u5834\u6240\u306b\u7f6e\u304d\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/ Phase2: \u30c9\u30e9\u30c3\u30b0\u958b\u59cb \u2192 \u30a2\u30f3\u30ab\u30fc\u8a18\u9332\nif response.drag_started_by(egui::PointerButton::Primary) {\n    let (ppx, ppy) = self.stamp_paste_pos;\n    self.stamp_drag_anchor = Some((px as i32 - ppx as i32, py as i32 - ppy as i32));\n    return None;\n}<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/ \u30c9\u30e9\u30c3\u30b0\u4e2d\u306e\u4f4d\u7f6e\u66f4\u65b0\nif let Some((ax, ay)) = self.stamp_drag_anchor {\n    self.stamp_paste_pos = (\n        (cx as i32 - ax).max(0) as usize,\n        (cy as i32 - ay).max(0) as usize,\n    );\n}<\/pre>\n<p>\u3053\u308c\u3067\u3001\u30b9\u30bf\u30f3\u30d7\u306e\u3069\u3053\u3092\u63b4\u3093\u3067\u3082\u305d\u306e\u76f8\u5bfe\u4f4d\u7f6e\u3092\u4fdd\u3063\u305f\u307e\u307e\u52d5\u304d\u307e\u3059\u3002<code>.max(0)<\/code> \u3067\u5de6\u4e0a\u306b\u306f\u307f\u51fa\u3055\u306a\u3044\u3088\u3046\u306b\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<h5>\u70b9\u7dda\u306e\u67a0<\/h5>\n<p>\u9078\u629e\u7bc4\u56f2\u3068\u8cbc\u308a\u4ed8\u3051\u4f4d\u7f6e\u306e\u67a0\u306f\u3001<strong>\u767d\u3068\u9ed2\u3092\u4ea4\u4e92\u306b\u63cf\u3044\u305f\u70b9\u7dda<\/strong>\u306b\u3057\u3066\u3044\u307e\u3059\u3002\u30c9\u30c3\u30c8\u7d75\u306e\u80cc\u666f\u8272\u306f\u4f55\u8272\u306b\u306a\u308b\u304b\u5206\u304b\u3089\u306a\u3044\u306e\u3067\u3001\u767d\u3060\u3051\u30fb\u9ed2\u3060\u3051\u3060\u3068\u80cc\u666f\u3068\u540c\u5316\u3057\u3066\u898b\u3048\u306a\u304f\u306a\u308b\u3053\u3068\u304c\u3042\u308b\u3093\u3067\u3059\u3088\u306d\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">\/\/\/ \u70b9\u7dda\u306e\u77e9\u5f62\u30a2\u30a6\u30c8\u30e9\u30a4\u30f3\u3092\u63cf\u753b\uff08\u767d\u3068\u6697\u8272\u3092\u4ea4\u4e92\u306b\uff09\nfn draw_dashed_rect_outline(painter: &amp;egui::Painter, r: egui::Rect, dash: f32) {\n    let edges = [\n        (r.left_top(),    r.right_top()),\n        (r.right_top(),   r.right_bottom()),\n        (r.right_bottom(),r.left_bottom()),\n        (r.left_bottom(), r.left_top()),\n    ];\n    for (p0, p1) in edges {\n        let dx = p1.x - p0.x;\n        let dy = p1.y - p0.y;\n        let len = (dx * dx + dy * dy).sqrt();\n        if len &lt; 0.1 { continue; }\n        let steps = (len \/ dash).ceil() as usize;\n        for i in 0..steps {\n            let t0 = (i as f32 * dash) \/ len;\n            let t1 = ((i as f32 + 1.0) * dash \/ len).min(1.0);\n            let color = if i % 2 == 0 { egui::Color32::WHITE } else { egui::Color32::from_black_alpha(200) };\n            painter.line_segment(\n                [egui::pos2(p0.x + dx * t0, p0.y + dy * t0),\n                 egui::pos2(p0.x + dx * t1, p0.y + dy * t1)],\n                egui::Stroke::new(1.5, color),\n            );\n        }\n    }\n}<\/pre>\n<p>4 \u8fba\u3092\u305d\u308c\u305e\u308c <code>dash<\/code> \u306e\u9577\u3055\u3067\u5206\u5272\u3057\u3066\u3001\u5076\u6570\u756a\u76ee\u306f\u767d\u3001\u5947\u6570\u756a\u76ee\u306f\u9ed2\u306e\u7dda\u5206\u3092\u5f15\u304f\u3002egui \u306b\u306f\u7834\u7dda\u3092\u5f15\u304f API \u3082\u4e00\u5fdc\u3042\u308b\u306e\u3067\u3059\u304c\u30012 \u8272\u4ea4\u4e92\u306b\u3057\u305f\u304b\u3063\u305f\u306e\u3067\u81ea\u524d\u3067\u3059\u3002<\/p>\n<h5>\u78ba\u5b9a\uff1aApplyStamp<\/h5>\n<p>Phase 2 \u306e\u30ea\u30ea\u30fc\u30b9\u3067\u3001\u30d0\u30c3\u30d5\u30a1\u306e\u5404\u30c9\u30c3\u30c8\u3092\u300c(\u30aa\u30d5\u30bb\u30c3\u30c8, px, py, \u8272)\u300d\u306e 4 \u3064\u7d44\u306b\u5909\u63db\u3057\u3066 <code>ApplyStamp<\/code> \u3092\u8fd4\u3057\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"rust\">let stamp_pixels: Vec&lt;(usize, usize, usize, u8)&gt; = if let Some((sw, sh, pixels)) = &amp;self.stamp_buffer {\n    let (sw, sh) = (*sw, *sh);\n    (0..sh).flat_map(|row| {\n        let pixels_row = &amp;pixels[row];\n        (0..sw).filter_map(move |col| {\n            let bx = ppx + col;\n            let by = ppy + row;\n            if bx &gt;= block_px || by &gt;= block_px { return None; }\n            let off = ((top_row + by \/ 8) * 16 + (top_col + bx \/ 8)) * 16;\n            if off + 16 &gt; chr_len { return None; }\n            Some((off, bx % 8, by % 8, pixels_row[col]))\n        }).collect::&lt;vec&lt;_&gt;&gt;()\n    }).collect()\n} else { vec![] };&lt;\/vec&lt;_&gt;<\/pre>\n<p><code>ApplyLine<\/code> \u3068\u306e\u9055\u3044\u306f\u3001<strong>\u30c9\u30c3\u30c8\u3054\u3068\u306b\u8272\u3092\u6301\u3063\u3066\u3044\u308b<\/strong>\u3053\u3068\u3060\u3051\u3067\u3059\u3002<code>ApplyLine<\/code> \u306f\u300c\u63cf\u753b\u8272\u3067\u5857\u308b\u300d\u306a\u306e\u3067\u8272\u306f 1 \u3064\u3067\u3059\u304c\u3001\u30b9\u30bf\u30f3\u30d7\u306f\u30b3\u30d4\u30fc\u5143\u306e\u8272\u3092\u305d\u306e\u307e\u307e\u6301\u3063\u3066\u304d\u307e\u3059\u3002<code>apply_action()<\/code> \u5074\u306e\u51e6\u7406\u3082 <code>apply_line()<\/code> \u3068\u307b\u307c\u540c\u3058\u3067\u3001\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8 \u2192 <code>push_undo_batch()<\/code> \u2192 <code>encode_dot()<\/code> \u306e\u9806\u3067\u3059\u3002<\/p>\n<p>\u30ad\u30e3\u30f3\u30d0\u30b9\u304b\u3089\u306f\u307f\u51fa\u3059\u90e8\u5206\u306f <code>bx &gt;= block_px<\/code> \u3067\u6368\u3066\u3066\u3044\u308b\u306e\u3067\u3001\u7aef\u306b\u62bc\u3057\u3066\u3082\u30af\u30ea\u30c3\u30d7\u3055\u308c\u308b\u3060\u3051\u3067\u58ca\u308c\u307e\u305b\u3093\u3002<\/p>\n<h4>\u307e\u3068\u3081<\/h4>\n<ul>\n<li>\u56f3\u5f62\u30c4\u30fc\u30eb\u306f\u300c\u30c9\u30e9\u30c3\u30b0\u4e2d\u306f painter \u3067\u30d7\u30ec\u30d3\u30e5\u30fc\u3060\u3051\u3001\u30ea\u30ea\u30fc\u30b9\u3067 <code>ApplyLine<\/code>\u300d\u3002CHR \u3082\u30a2\u30f3\u30c9\u30a5\u30b9\u30bf\u30c3\u30af\u3082\u6c5a\u3055\u306a\u3044<\/li>\n<li>\u30d7\u30ec\u30d3\u30e5\u30fc\u3068\u78ba\u5b9a\u304c\u540c\u3058 <code>shape_dots()<\/code> \u3092\u901a\u308b\u306e\u3067\u7d50\u679c\u304c\u305a\u308c\u306a\u3044<\/li>\n<li>\u30ea\u30ea\u30fc\u30b9\u6642\u306f <code>interact_pointer_pos()<\/code> \u304c <code>None<\/code> \u306b\u306a\u308b\u3053\u3068\u304c\u3042\u308b\u306e\u3067\u3001<code>button_released()<\/code> + <code>hover_pos()<\/code> \u3067\u7d42\u70b9\u3092\u53d6\u308b<\/li>\n<li>\u76f4\u7dda\u306f Bresenham\u3001\u77e9\u5f62\u306f <code>kind<\/code> \u3067\u67a0 \/ \u5857\u308a \/ \u30d1\u30bf\u30fc\u30f3\u3092\u5207\u308a\u66ff\u3048\u3001\u6955\u5186\u306f\u5f0f\u3092\u76f4\u63a5\u4f7f\u3063\u3066\u5857\u308a\u306f\u30b9\u30ad\u30e3\u30f3\u30e9\u30a4\u30f3\u3001\u8f2a\u90ed\u306f\u884c\u3068\u5217\u306e\u4e21\u65b9\u306e\u7aef\u70b9<\/li>\n<li>\u5857\u308a\u3064\u3076\u3057\u306f\u8272\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u6bd4\u8f03\u306e 4 \u65b9\u5411 BFS\u3002\u30c7\u30b3\u30fc\u30c9\u6e08\u307f\u30d6\u30ed\u30c3\u30af\u4e0a\u3067\u63a2\u7d22<\/li>\n<li>\u30b9\u30bf\u30f3\u30d7\u306f 4 \u3064\u306e <code>Option<\/code> \u3067\u30d5\u30a7\u30fc\u30ba\u3092\u8868\u73fe\u3057\u3001\u30a2\u30f3\u30ab\u30fc\u3067\u81ea\u7136\u306a\u30c9\u30e9\u30c3\u30b0\u30012 \u8272\u306e\u70b9\u7dda\u3067\u8996\u8a8d\u6027\u3092\u78ba\u4fdd<\/li>\n<li>\u5168\u90e8 <code>(\u30aa\u30d5\u30bb\u30c3\u30c8, px, py[, \u8272])<\/code> \u306e\u30ea\u30b9\u30c8\u306b\u843d\u3068\u3057\u3066 <code>push_undo_batch()<\/code> + <code>encode_dot()<\/code> \u306b\u6d41\u3059\u3060\u3051<\/li>\n<\/ul>\n<p>\u66f8\u304d\u8fbc\u307f\u306e\u51fa\u53e3\u3092 <code>encode_dot()<\/code>\u3001\u30a2\u30f3\u30c9\u30a5\u306e\u5165\u53e3\u3092 <code>push_undo_batch()<\/code> \u306b\u7d5e\u3063\u3066\u304a\u3044\u305f\u304a\u304b\u3052\u3067\u3001\u30c4\u30fc\u30eb\u3092 1 \u3064\u8db3\u3059\u305f\u3073\u306b\u3084\u308b\u3053\u3068\u304c\u300c<strong>\u30c9\u30c3\u30c8\u5ea7\u6a19\u306e\u30ea\u30b9\u30c8\u3092\u4f5c\u308b\u95a2\u6570\u3092\u66f8\u304f<\/strong>\u300d\u3060\u3051\u306b\u306a\u308a\u307e\u3057\u305f\u3002\u6955\u5186\u30c4\u30fc\u30eb\u306a\u3093\u304b\u306f\u672c\u5f53\u306b <code>ellipse_dots()<\/code> \u3092\u8db3\u3057\u3066 <code>shape_dots()<\/code> \u306e <code>match<\/code> \u306b 2 \u884c\u52a0\u3048\u305f\u3060\u3051\u3067\u3059\u3002<\/p>\n<p>\u6b21\u56de\u306f <strong>PNG \u30a4\u30f3\u30dd\u30fc\u30c8<\/strong>\u3002Aseprite \u3067\u63cf\u3044\u305f\u7d75\u3092\u305d\u306e\u307e\u307e\u653e\u308a\u8fbc\u307f\u305f\u3044\u3001\u3068\u3044\u3046\u6b32\u671b\u3092\u53f6\u3048\u308b\u305f\u3081\u306e\u30013 \u3064\u306e\u30de\u30c3\u30d4\u30f3\u30b0\u6226\u7565\u3068\u900f\u904e\u51e6\u7406\u306e\u8a71\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<p>\u3067\u306f\u3067\u306f\u3041\u3002<\/p>\n<p>\u307e\u305f\u307e\u305f\u3041\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u3069\u3082\u3067\u3059\u3002 \u524d\u56de\u306f\u30da\u30f3\u30c4\u30fc\u30eb\u3068\u30a2\u30f3\u30c9\u30a5\u306e\u8a2d\u8a08\u3067\u3057\u305f\u3002\u4eca\u56de\u306f\u305d\u306e\u4e0a\u306b\u4e57\u3063\u3066\u3044\u308b\u56f3\u5f62\u30c4\u30fc\u30eb\u3001\u3064\u307e\u308a\u76f4\u7dda\u30fb\u77e9\u5f62\u30fb\u6955\u5186\u30fb\u5857\u308a\u3064\u3076\u3057\u30fb\u30b9\u30bf\u30f3\u30d7\u306e\u5b9f\u88c5\u3092\u307e\u3068\u3081\u305f\u5f62\u306b\u306a\u308a\u307e\u3059\u3002 \u300c\u63cf\u753b\u30c4\u30fc\u30eb\u3092\u539a\u304f\u3057\u305f\u3044\u300d\u3068\u3044\u3046\u306e\u304c R-CHR \u3092\u4f5c\u3063 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":12826,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[299],"tags":[308,169,381,39,390,389,388,78,118],"class_list":["post-12789","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-rust","tag-gui","tag-mac","tag-nes","tag-39","tag-390","tag-389","tag-388","tag-78","tag-118"],"_links":{"self":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/12789","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12789"}],"version-history":[{"count":3,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/12789\/revisions"}],"predecessor-version":[{"id":12833,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/12789\/revisions\/12833"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/media\/12826"}],"wp:attachment":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12789"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12789"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12789"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}