Bicameral Engine
GPU-resident engine for a magic-research open-world game
Loading...
Searching...
No Matches
reaction_wide_cell.h
Go to the documentation of this file.
1// reaction_wide_cell.h — 成分の数に上限が無いセル(CPU リファレンス。T-0175・D-401・D-418・02 §3)。
2//
3// 反応の核(shaders/common/reaction.hlsli)はセルの形を Cell 型で受け取る。GPU と今の多重解像度の世界は RxCell
4// (インラインの RX_MAX_CELL_SPECIES 個まで)、ここの RxWideCell は成分を std::vector に持ち、何種でも足せる。
5// 核が形ごとに呼ぶ道具(RxHasRoomForSpecies・RxCellWithRoom・RxEmptyCellLike・RxEmptyUsage)の RxWideCell 版を
6// 同じ名前空間に置くので、核のテンプレートは引数依存の名前探索でこちらを見つける。
7//
8// 約束は RxCell と同じ: 成分は物質 ID の昇順・物質量が 0 の成分は無い・speciesCount 個より後ろの要素は読まない。
9// 成分が RX_MAX_CELL_SPECIES 以下の間は、RxCell で刻んだ結果とビット単位で同じになる(RxWidenCell / RxNarrowCell で行き来できる)。
10// GPU の頁ごとの溢れ領域(インライン K + 溢れ)は T-0176 で、このセルと毎刻みビット一致させる。
11#pragma once
12
13#include <cstdint>
14#include <vector>
15
16#include "common/reaction.hlsli"
17
19
20 struct RxWideCell {
21 int64_t energy = 0; // mJ(熱 + 化学)
22 uint32_t speciesCount = 0;
23 std::vector<uint32_t> species; // 大きさは speciesCount 以上
24 std::vector<uint64_t> amounts; // µmol
25 };
26
27 // 候補が使う量(RxUsage の上限なし版。添字 = 成分の位置)
28 struct RxWideUsage {
29 std::vector<uint64_t> amounts;
30 uint64_t heat = 0;
31 };
32
33 using RxWideWaitStep = RxWaitStepOf<RxWideCell>;
34
35 // --- 核が呼ぶ、セルの形ごとの道具(reaction.hlsli の「セルの形ごとの道具」の RxWideCell 版)---
36
37 inline bool RxHasRoomForSpecies(const RxWideCell& /*cell*/) {
38 return true;
39 }
40
42 const size_t wanted = static_cast<size_t>(cell.speciesCount) + 1;
43 if (cell.species.size() < wanted) {
44 cell.species.resize(wanted, 0);
45 cell.amounts.resize(wanted, 0);
46 }
47
48 return cell;
49 }
50
51 inline RxWideCell RxEmptyCellLike(const RxWideCell& /*cell*/, int64_t energy) {
52 return {.energy = energy, .speciesCount = 0, .species = {}, .amounts = {}};
53 }
54
55 inline RxWideUsage RxEmptyUsage(const RxWideCell& cell) {
56 return {.amounts = std::vector<uint64_t>(cell.speciesCount, 0), .heat = 0};
57 }
58
59 // --- 行き来と比べる ---
60
61 inline RxWideCell RxMakeEmptyWideCell(int64_t energy) {
62 return {.energy = energy, .speciesCount = 0, .species = {}, .amounts = {}};
63 }
64
65 inline RxWideCell RxWidenCell(const RxCell& cell) {
66 RxWideCell wide = RxMakeEmptyWideCell(cell.energy);
67 wide.speciesCount = cell.speciesCount;
68 wide.species.assign(cell.species, cell.species + cell.speciesCount);
69 wide.amounts.assign(cell.amounts, cell.amounts + cell.speciesCount);
70
71 return wide;
72 }
73
74 // インラインに入りきるか(RxNarrowCell できるか)
75 inline bool RxFitsInline(const RxWideCell& cell) {
76 return cell.speciesCount <= RX_MAX_CELL_SPECIES;
77 }
78
79 // インラインの形にする(入りきる時だけ呼ぶ。使わない枠は 0 = RxMakeEmptyCell と同じ)
80 inline RxCell RxNarrowCell(const RxWideCell& cell) {
81 FX_ASSERT(RxFitsInline(cell));
82 RxCell narrow = RxMakeEmptyCell(cell.energy);
83 narrow.speciesCount = cell.speciesCount;
84 for (uint32_t i = 0; i < cell.speciesCount; ++i) {
85 narrow.species[i] = cell.species[i];
86 narrow.amounts[i] = cell.amounts[i];
87 }
88
89 return narrow;
90 }
91
92 // 2 つのセルが同じか(speciesCount 個より後ろは見ない)
93 inline bool RxSameCell(const RxWideCell& a, const RxWideCell& b) {
94 if (a.energy != b.energy || a.speciesCount != b.speciesCount)
95 return false;
96
97 for (uint32_t i = 0; i < a.speciesCount; ++i) {
98 if (a.species[i] != b.species[i] || a.amounts[i] != b.amounts[i])
99 return false;
100 }
101
102 return true;
103 }
104
105} // namespace bicameral::reaction
RxWideCell RxMakeEmptyWideCell(int64_t energy)
bool RxFitsInline(const RxWideCell &cell)
RxWideCell RxWidenCell(const RxCell &cell)
RxWideCell RxCellWithRoom(RxWideCell cell)
bool RxSameCell(const RxWideCell &a, const RxWideCell &b)
RxWideCell RxEmptyCellLike(const RxWideCell &, int64_t energy)
RxCell RxNarrowCell(const RxWideCell &cell)
RxWideUsage RxEmptyUsage(const RxWideCell &cell)
RxWaitStepOf< RxWideCell > RxWideWaitStep
bool RxHasRoomForSpecies(const RxWideCell &)
std::vector< uint32_t > species
std::vector< uint64_t > amounts