繪製與畫布
兩條路線:PIDS 螢幕用 Text / Texture / Rect 串流 API 直接輸出;像素級內容(LCD、點陣螢幕)用 GraphicsTexture + Gfx2D 原生光柵。
螢幕座標系內容(PIDS 文字行、貼圖區塊)→ Text/Texture:一條繪製記錄,宿主用與 JS 完全相同的程式碼路徑回放。像素級內容(車輛 LCD、動態點陣螢幕、圖表)→ GraphicsTexture 自繪像素,經 Gfx2D 光柵化圖元,只把髒矩形上傳 GPU。
Text / Texture / Rect(PIDS)
<mtr/text.hpp> 是 JS TextWrapper / TextureWrapper / Rect 串流 API 的 1:1 移植——方法名按 C++ 慣例採 snake_case,鏈式呼叫:
mtr::Text::create()
.text("Tsim Sha Tsui")
.scale(1.725)
.size(100, 9)
.stretch_xy()
.font_mc()
.color(0xFC9700)
.pos(3, rowY)
.draw(ctx);
| Text 方法 | 對應 JS | 說明 |
|---|---|---|
.text(str[, len]) | .text() | UTF-8 文字 |
.scale(s) | .scale() | 整體縮放 |
.left_align() / .center_align() / .right_align() | 同名 | 對齊(預設置中) |
.shadowed() / .bold() / .italic() | 同名 | 字型樣式 |
.stretch_xy() / .scale_xy() / .wrap_text() / .marquee(duration) | 同名 | 溢位模式(跑馬燈可用 .with_marquee_progress(p) 固定進度) |
.font(id) / .font_mc() | 同名 | 資源字型(如 .font("jsblock:shanghai"))/ MC 內建字型 |
.color(argb) | 同名 | 顏色(ARGB) |
.pos(x, y) / .size(w, h) | 同名 | 螢幕座標與包圍框 |
.z_order(z) / .layer(l) | 同名 | 層級;z=-1 時由上下文自動分配 |
.render_type("LIGHT_1") | .renderType() | 字串渲染層(QueuedRenderLayer.valueOf 等價;未知名稱擲出例外) |
.natural_light() | .naturalLight() | 取環境光照而非最大渲染亮度 |
| Texture 方法 | 說明 |
|---|---|
.texture(id) | 貼圖資源 id(如 "mtr:textures/block/pids.png") |
.uv(u1, v1, u2, v2) | UV 子矩形 |
.color(argb) | 染色 |
.pos(x, y) / .size(w, h) | 位置與尺寸 |
.z_order(z) / .layer(l) | 層級 |
.render_type("LIGHT_1") / .natural_light() | 字串渲染層 / 環境光照(同 Text) |
Rect(純色矩形)
mtr::Rect 對應上游 JS 的 Rect 類別(原名 Rectangle,上游 v2.3.0-prerelease.2 起更名,Java 類別名不變)——繪製 mtr:white.png 全 UV 四邊形並整體染色,是底色塊、分隔條、狀態色帶的最輕途徑:
mtr::Rect::create()
.color(0xFF00539F) // 不透明染色(預設 ARGB_WHITE)
.pos(2, rowY + 18)
.size(pids.width() - 4, 1) // 預設 20×20
.draw(ctx);
| Rect 方法 | 說明 |
|---|---|
.color(argb) | 染色(預設白色 ARGB_WHITE) |
.pos(x, y) / .size(w, h) | 位置與尺寸(預設 20×20) |
.render_type("LIGHT_2") | 字串渲染層(預設 LIGHT_2) |
.natural_light() / .z_order(z) | 環境光照 / 層級(z=-1 自動分配) |
對應的上下文方法(PidsContext):
ctx.set_auto_z_ordering(bool)—— 自動 z 序(預設開啟)ctx.set_z_order_step(step)—— 自動 z 序步長(預設 0.0002)
渲染層(與 mtr::Matrices 無關的 2D 層列舉 MtrRenderLayer):MTR_LAYER_TEXT(文字)、MTR_LAYER_LIGHT(發光體)、MTR_LAYER_EXTERIOR / MTR_LAYER_INTERIOR(外觀 / 內裝),與 MTR 的 QueuedRenderLayer 一致。
Matrices 與模型繪製
<mtr/matrices.hpp> 對應 JS 的全域 Matrices:變換推入堆疊、compile() 把目前堆疊編譯成一組矩陣寫進幀矩陣記憶體區:
mtr::Matrices m;
m.translate(0.5f, 1.0f, 0.0f);
m.rotate_y_degrees(90.0f);
m.scale(1.0f, 1.0f, 1.0f);
ctx.draw_car_model(model_handle, car_index, &m); // 車輛
ctx.draw_model(model_handle, &m); // 裝飾 / 電梯
| 成員 | 說明 |
|---|---|
translate(x, y, z) / scale(x, y, z) | 平移 / 縮放 |
rotate_x / rotate_y / rotate_z(radians) | 旋轉(弧度) |
rotate_x_degrees / …_y… / …_z…(deg) | 旋轉(角度) |
compile() | 把目前姿態編譯進幀(傳回矩陣組索引;傳給 draw 呼叫) |
車輛上下文另有 draw_bogie_model(model, car, bogie, matrices)(轉向架)、play_car_sound(sound, car, x, y, z, volume, pitch) 與 play_ann_sound(sound, volume, pitch)(僅乘坐玩家可聽見的報站廣播)。
模型控制代碼來自宿主服務:ctx.host()->acquire_model(user, "namespace:path/model.json") 取得、release_model(user, handle) 釋放;acquire_quad_model(...) 可用 4 個模型空間頂點 + UV 建構宿主持有的貼圖面片(把 GraphicsTexture 變成可貼到車廂上的螢幕)。細節見 C ABI 與宿主服務。
GraphicsTexture(像素畫布)
<mtr/gfx.hpp> 的 GraphicsTexture 把像素緩衝留在你的模組裡,遊戲側只收髒矩形上傳——像素資料不逐幀跨邊界搬運:
struct LcdState {
mtr::GraphicsTexture tex; // 建議放 State:與實例同生命週期
};
void create(mtr::VehicleContext& ctx, LcdState& s, const mtr::Vehicle&) {
s.tex.create(ctx.input(), 512, 128); // 同時向宿主註冊 GPU 紋理
// 把紋理貼到車廂:host->acquire_quad_model(...) → draw_car_model(...)
}
void render(mtr::VehicleContext& ctx, LcdState& s, const mtr::Vehicle& vehicle) {
// 1. 畫像素(Gfx2D 或直接 set_pixel)
// 2. 只上傳變化區域:
s.tex.upload(ctx.frame());
}
| 成員 | 說明 |
|---|---|
create(input, w, h) | 配置像素緩衝區(BGRA8 列主序)並在宿主側建立 GPU 紋理,傳回後整體視為髒 |
pixels() / pixels32() | 直接像素指標(uint8_t* / uint32_t*) |
set_pixel(x, y, argb) | 寫入單一像素並自動累計髒區 |
upload(frame) | 把目前髒矩形寫入幀像素記憶體區(一條 JCM_DRAW_TEXTURE_UPLOAD 記錄),隨後髒區重置 |
last_upload_bytes() | 上次上傳的位元組數——效能觀測利器 |
close(input) / 解構 | 釋放宿主 GPU 紋理 |
handle() / width() / height() / texture_bytes() | 宿主紋理控制代碼與尺寸資訊 |
upload() 只搬運自上次上傳以來變化過的包圍框。靜態背景畫一次即可;每幀只動需要動的條帶(跑馬燈、閃爍段、進度條)。車輛 LCD 閃爍/輪播如果只改一小條,上傳量就只有那一小條。
同一標頭檔還提供 LcdCanvas——基於內建 5×7 點陣字型的 LCD 畫筆(可設定亮/滅顏色),適合經典點陣螢幕。
Gfx2D 軟體光柵器
<mtr/gfx2d.hpp> 把 java.awt.Graphics2D 的常用子集實作為確定性軟體光柵器,直接畫在 GraphicsTexture 上。JS 資源包裡的 fillRect / fillOval / drawLine / GeneralPath / clip / drawString 邏輯可以機械式地移植過來:
mtr::Gfx2D g(s.tex, ctx.host(), "jsblock:shanghai"); // 畫布 + 宿主字型
g.set_color(mtr::clr(12, 28, 44)); // 深色底
g.fill_rect(0, 0, W, H);
g.push_clip(8, 8, W - 16, 40); // 裁切堆疊
g.set_color(mtr::clra(255, 205, 66, 255));
g.draw_text_centered(W / 2, 30, 18.0, "下一站 Next");
g.pop_clip();
| 圖元 | 說明 |
|---|---|
fill_rect / fill_round_rect / draw_round_rect | 矩形(圓角弧半徑參數) |
fill_oval / draw_oval | 橢圓填充 / 描邊(線寬) |
draw_line(x1, y1, x2, y2, lw) | 線段 |
fill_polygon(xs, ys, n) | 多邊形填充(GeneralPath 等價) |
push_clip / pop_clip | 裁切框堆疊;所有圖元先裁切再光柵化,髒區同樣受裁切約束 |
draw_text / draw_text_centered / draw_text_compressed / draw_mixed_text | 文字(見下節字型) |
draw_logo_badge(x, y, w, h, bg, fg) | 圓角徽章底 |
full_aa() / no_aa() | 一像素覆蓋率抗鋸齒開關(預設關閉,對應上游 fullAA() / noAA()):橢圓 / 圓角矩形 / 描邊 / 多邊形填充的邊緣做整數 src-over 混合;文字恆為宿主 TTF 抗鋸齒,不受影響 |
顏色輔助函式:mtr::clr(r, g, b) / mtr::clra(r, g, b, a)(不透明 / 帶 alpha),對應 JS config.js 裡的同名函式。半透明顏色走 src-over 合成;不透明顏色有快速路徑。
字型體系
三層字型,按可用性自動降級:
| 層級 | 涵蓋 | 說明 |
|---|---|---|
| 資源字型(首選) | 全 UTF-8 | 給 Text::font("jsblock:shanghai")、Gfx2D 建構子的第三個參數傳字型資源 id:用宿主的真實 FontMetrics 與 drawString,保留字距、基準線、壓縮、alpha 與裝置裁切——和 JS 端同一字型管線 |
| 宿主 TTF 回呼 | CJK 等 | 無資源字型時,CJK 字形經宿主服務 rasterize_text 光柵化(對應 JCM FontManager 的 TTF 集) |
| 內建 5×7 點陣字型 | ASCII / 拉丁 | 按請求尺寸縮放、按字形寬窄給比例步進(窄 i/l/.,寬 m/W)——text_width() 與實際繪製用同一組數字,JS 的自適應字級 / 5% 壓縮版面配置演算法可原樣移植;CJK 無宿主時退化為佔位框 |
內建字型的度量約定:ascent = 0.78 em、descent = 0.22 em(≈ Arial / HanSans);CJK 全形 1.0 em 步進。資源字型的度量(measure_font_text 宿主服務)按真實字型計算。
接下來:mtr::Api 與 Java 互通作業 —— 快照之外的一切。