wall auto-tiling experimentation

This commit is contained in:
jacob 2026-01-10 06:46:30 -06:00
parent 574f591666
commit bfbc7cf865
8 changed files with 194 additions and 113 deletions

View File

@ -754,7 +754,7 @@
// Based on Jon Maiga's "mx3"
// https://jonkagstrom.com/mx3/mx3_rev2.html
u64 MixU64(u64 seed)
Inline u64 MixU64(u64 seed)
{
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
@ -763,7 +763,7 @@ u64 MixU64(u64 seed)
return seed;
}
u64 MixU64s(u64 seed_a, u64 seed_b)
Inline u64 MixU64s(u64 seed_a, u64 seed_b)
{
return MixU64((seed_a * 3) + seed_b);
}

View File

@ -76,6 +76,39 @@ u32 countof(T arr[N])
#define ClampI64(...) clamp(__VA_ARGS__)
#define ClampF64(...) clamp(__VA_ARGS__)
#define MatchFloor(a, b) all(floor(a) == floor(b))
////////////////////////////////////////////////////////////
//~ Float ops
//- Round
#define RoundF32(v) round(v)
#define RoundF64(v) round(v)
//- Floor
#define FloorF32(v) floor(v)
#define FloorF64(v) floor(v)
//- Ceil
#define CeilF32(v) ceil(v)
#define CeilF64(v) ceil(v)
//- Trunc
#define TruncF32(v) trunc(v)
#define TruncF64(v) trunc(v)
//- Mod
#define ModF32(v, m) fmod((v), (m))
#define ModF64(v, m) fmod((v), (m))
//- Abs
#define AbsF32(v) abs(v)
#define AbsF64(v) abs(v)
//- Sign
#define SignF32(v) sign(v)
#define SignF64(v) sign(v)
////////////////////////////////////////////////////////////
//~ Derivative helpers
@ -84,7 +117,7 @@ u32 countof(T arr[N])
////////////////////////////////////////////////////////////
//~ Color helpers
Vec4 Vec4FromU32(u32 v)
Inline Vec4 Vec4FromU32(u32 v)
{
Vec4 result = 0;
result.x = ((v >> 0) & 0xFF) / 255.0;
@ -94,7 +127,7 @@ Vec4 Vec4FromU32(u32 v)
return result;
}
u32 U32FromVec4(Vec4 v)
Inline u32 U32FromVec4(Vec4 v)
{
u32 result = 0;
result |= (((u32)(v.x * 255.0)) & 0xFF) << 0;
@ -104,7 +137,7 @@ u32 U32FromVec4(Vec4 v)
return result;
}
f32 LinearFromSrgbF32(f32 srgb)
Inline f32 LinearFromSrgbF32(f32 srgb)
{
f32 result;
if (srgb <= 0.04045f)
@ -118,7 +151,7 @@ f32 LinearFromSrgbF32(f32 srgb)
return result;
}
Vec4 LinearFromSrgb(Vec4 srgb)
Inline Vec4 LinearFromSrgb(Vec4 srgb)
{
Vec4 result;
result.x = LinearFromSrgbF32(srgb.x);
@ -128,7 +161,7 @@ Vec4 LinearFromSrgb(Vec4 srgb)
return result;
}
Vec4 Premul(Vec4 v)
Inline Vec4 Premul(Vec4 v)
{
Vec4 result;
result.rgb = v.rgb * v.a;
@ -139,7 +172,7 @@ Vec4 Premul(Vec4 v)
////////////////////////////////////////////////////////////
//~ Vertex ID helpers
Vec2 RectUvFromVertexId(u32 id)
Inline Vec2 RectUvFromVertexId(u32 id)
{
static const Vec2 uvs[4] = {
Vec2(0, 0),
@ -153,7 +186,7 @@ Vec2 RectUvFromVertexId(u32 id)
////////////////////////////////////////////////////////////
//~ Ndc helpers
Vec2 NdcFromPos(Vec2 pos, Vec2 size)
Inline Vec2 NdcFromPos(Vec2 pos, Vec2 size)
{
Vec2 result;
result = pos / size;
@ -162,7 +195,7 @@ Vec2 NdcFromPos(Vec2 pos, Vec2 size)
return result;
}
Vec2 NdcFromUv(Vec2 uv)
Inline Vec2 NdcFromUv(Vec2 uv)
{
Vec2 result;
result = uv;

View File

@ -142,11 +142,11 @@ void S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta)
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
{
i32 src_tile_x = tile_x - range.p0.x;
Vec2I32 src_tile_pos = VEC2I32(src_tile_x, src_tile_y);
Vec2 src_tile_pos = VEC2(src_tile_x, src_tile_y);
i32 src_tile_idx = S_TileIdxFromTilePos(src_tile_pos);
u8 src_tile = delta->raw_tiles[src_tile_idx];
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
Vec2 tile_pos = VEC2(tile_x, tile_y);
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
world->tiles[tile_idx] = src_tile;
}
@ -161,7 +161,7 @@ void S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta)
{
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
{
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
Vec2 tile_pos = VEC2(tile_x, tile_y);
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
world->tiles[tile_idx] = (u8)tile;
}

View File

@ -1,17 +1,9 @@
////////////////////////////////////////////////////////////
//~ Tile helpers
Vec2I32 S_TilePosFromWorldPos(Vec2 p)
i32 S_TileIdxFromTilePos(Vec2 p)
{
Vec2I32 result;
result.x = ClampI32((p.x + S_WorldPitch * ((f32)S_WorldPitch / (f32)S_TilesPitch)) * 2, 0, S_TilesPitch - 1);
result.y = ClampI32((p.y + S_WorldPitch * ((f32)S_WorldPitch / (f32)S_TilesPitch)) * 2, 0, S_TilesPitch - 1);
return result;
}
i32 S_TileIdxFromTilePos(Vec2I32 p)
{
i32 result = ClampI32(p.x + (p.y * S_TilesPitch), 0, S_TilesCount);
i32 result = ClampI32(FloorF32(p.x) + (FloorF32(p.y) * S_TilesPitch), 0, S_TilesCount);
return result;
}

View File

@ -2,7 +2,11 @@
//~ Tile types
#define S_WorldPitch 64.0
#define S_TilesPitch (S_WorldPitch * 2)
#define S_TilesPerMeter 2.0
#define S_TilesPerSqMeter (V_TilesPerMeter * V_TilesPerMeter)
#define S_TilesPitch (S_WorldPitch * S_TilesPerMeter)
#define S_TilesCount (S_TilesPitch * S_TilesPitch)
#define S_TilesXMacro(X) \
@ -23,8 +27,7 @@ Enum(S_TileKind)
////////////////////////////////////////////////////////////
//~ Tile helpers
Vec2I32 S_TilePosFromWorldPos(Vec2 p);
i32 S_TileIdxFromTilePos(Vec2I32 p);
i32 S_TileIdxFromTilePos(Vec2 p);
#if IsLanguageC
String S_TileNameFromKind(S_TileKind kind);

View File

@ -933,6 +933,16 @@ void V_TickForever(WaveLaneCtx *lane)
frame->xf.cell_to_world = InvertXform(frame->xf.world_to_cell);
}
// World <-> tile
// TODO: This never changes, should be #defined (so shaders don't need to read it every frame)
frame->xf.world_to_tile = XformIdentity;
frame->xf.tile_to_world = XformIdentity;
{
frame->xf.world_to_tile = ScaleXform(frame->xf.world_to_tile, VEC2(S_TilesPerMeter, S_TilesPerMeter));
frame->xf.world_to_tile = TranslateXform(frame->xf.world_to_tile, VEC2((S_WorldPitch / 2.0), (S_WorldPitch / 2.0)));
frame->xf.tile_to_world = InvertXform(frame->xf.world_to_tile);
}
//////////////////////////////
//- Update cursors / selection
@ -990,9 +1000,8 @@ void V_TickForever(WaveLaneCtx *lane)
{
// TODO: Fix clamp when both start & end are outside of world
Rng2I32 tile_range = Zi;
tile_range.p0 = S_TilePosFromWorldPos(last_frame->world_selection.p0);
tile_range.p1 = S_TilePosFromWorldPos(last_frame->world_selection.p1);
tile_range.p1 = AddVec2I32(tile_range.p1, VEC2I32(1, 1));
tile_range.p0 = Vec2I32FromVec(FloorVec2(MulXformV2(frame->xf.world_to_tile, last_frame->world_selection.p0)));
tile_range.p1 = Vec2I32FromVec(CeilVec2(MulXformV2(frame->xf.world_to_tile, last_frame->world_selection.p1)));
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
cmd->delta.kind = S_DeltaKind_Tile;
@ -2221,12 +2230,12 @@ void V_TickForever(WaveLaneCtx *lane)
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
{
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
Vec2I32 tile_pos = S_TilePosFromWorldPos(frame->world_cursor);
Vec2 tile_pos = MulXformV2(frame->xf.world_to_tile, frame->world_cursor);
Vec2 cell_pos = MulXformV2(frame->xf.world_to_cell, frame->world_cursor);
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
UI_BuildLabelF("Camera pos: %F", FmtFloat2(frame->camera_pos));
UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor));
UI_BuildLabelF("Cursor tile pos: %F", FmtSint2(tile_pos));
UI_BuildLabelF("Cursor tile pos: %F", FmtFloat2(tile_pos));
UI_BuildLabelF("Cursor tile idx: %F", FmtSint(tile_idx));
UI_BuildLabelF("Cursor cell pos: %F", FmtFloat2(cell_pos));
UI_BuildLabelF("Hovered ent: %F", S_FmtKey(hovered_ent->key));
@ -3223,7 +3232,15 @@ void V_TickForever(WaveLaneCtx *lane)
G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_ShaderRead);
}
// Flags
V_GpuFlag gpu_flags = 0;
if (frame->show_console)
{
gpu_flags |= V_GpuFlag_DebugDraw;
}
// Constants
G_SetConstant(frame->cl, V_ShaderConst_GpuFlags, gpu_flags);
G_SetConstant(frame->cl, V_ShaderConst_State, gpu_state_ref);
G_SetConstant(frame->cl, V_ShaderConst_Params, gpu_params_ref);
G_SetConstant(frame->cl, V_ShaderConst_NoiseTex, G_BasicNoiseTexture());

View File

@ -73,10 +73,6 @@ ComputeShader2D(V_BackdropCS, 8, 8)
const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1));
const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
const Vec4 grid_color = LinearFromSrgb(Vec4(0, 0, 0, 1));
const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1));
const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1));
const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1));
Vec2 ui_pos = SV_DispatchThreadID + Vec2(0.5, 0.5);
if (ui_pos.x < params.target_size.x && ui_pos.y < params.target_size.y)
@ -84,21 +80,18 @@ ComputeShader2D(V_BackdropCS, 8, 8)
Vec4 result = Vec4(0.025, 0.025, 0.025, 1);
Vec2 world_pos = mul(params.xf.ui_to_world, Vec3(ui_pos, 1));
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
Vec2I32 tile_pos_right = tile_pos;
tile_pos_right.x += 1;
Vec2 tile_pos = mul(params.xf.world_to_tile, Vec3(world_pos, 1));
S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
S_TileKind tile_right = tiles.Load(Vec3I32(tile_pos_right, 0));
S_TileKind tile = tiles.Load(Vec3(tile_pos, 0));
f32 half_thickness = 1;
f32 half_bounds_size = S_WorldPitch * 0.5;
Vec2 bounds_screen_p0 = mul(params.xf.world_to_ui, Vec3(-half_bounds_size, -half_bounds_size, 1));
Vec2 bounds_screen_p1 = mul(params.xf.world_to_ui, Vec3(half_bounds_size, half_bounds_size, 1));
bool is_in_bounds = ui_pos.x > (bounds_screen_p0.x - half_thickness) &&
ui_pos.y > (bounds_screen_p0.y - half_thickness) &&
ui_pos.x < (bounds_screen_p1.x + half_thickness) &&
ui_pos.y < (bounds_screen_p1.y + half_thickness);
ui_pos.y > (bounds_screen_p0.y - half_thickness) &&
ui_pos.x < (bounds_screen_p1.x + half_thickness) &&
ui_pos.y < (bounds_screen_p1.y + half_thickness);
if (is_in_bounds)
{
// Grid checker
@ -128,78 +121,51 @@ ComputeShader2D(V_BackdropCS, 8, 8)
}
result = colors[color_idx];
}
// Grid outline
// {
// Vec2 grid_screen_p0 = mul(params.xf.world_to_ui, Vec3(floor(world_pos), 1));
// Vec2 grid_screen_p1 = mul(params.xf.world_to_ui, Vec3(ceil(world_pos), 1));
// f32 grid_dist = 100000;
// grid_dist = min(grid_dist, abs(ui_pos.x - grid_screen_p0.x));
// grid_dist = min(grid_dist, abs(ui_pos.x - grid_screen_p1.x));
// grid_dist = min(grid_dist, abs(ui_pos.y - grid_screen_p0.y));
// grid_dist = min(grid_dist, abs(ui_pos.y - grid_screen_p1.y));
// if (grid_dist <= half_thickness)
// {
// result = grid_color;
// }
// }
// Axis
{
Vec2 zero_screen = mul(params.xf.world_to_ui, Vec3(0, 0, 1));
f32 x_dist = abs(ui_pos.x - zero_screen.x);
f32 y_dist = abs(ui_pos.y - zero_screen.y);
if (y_dist <= half_thickness)
{
result = x_axis_color;
}
else if (x_dist <= half_thickness)
{
result = y_axis_color;
}
}
// World bounds
{
f32 bounds_dist = 100000;
bounds_dist = min(bounds_dist, abs(ui_pos.x - bounds_screen_p0.x));
bounds_dist = min(bounds_dist, abs(ui_pos.x - bounds_screen_p1.x));
bounds_dist = min(bounds_dist, abs(ui_pos.y - bounds_screen_p0.y));
bounds_dist = min(bounds_dist, abs(ui_pos.y - bounds_screen_p1.y));
if (bounds_dist <= half_thickness)
{
result = bounds_color;
}
}
// Tile test
// TODO: Remove this
{
if (tile == S_TileKind_Floor)
S_TileKind tile_tl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y - 1, 0));
S_TileKind tile_tr = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y - 1, 0));
S_TileKind tile_br = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y + 1, 0));
S_TileKind tile_bl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y + 1, 0));
S_TileKind tile_t = tiles.Load(Vec3(tile_pos.x, tile_pos.y - 1, 0));
S_TileKind tile_r = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y, 0));
S_TileKind tile_b = tiles.Load(Vec3(tile_pos.x, tile_pos.y + 1, 0));
S_TileKind tile_l = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y, 0));
f32 tile_edge_dist = Inf;
S_TileKind edge_tile = tile;
if (tile_tl != tile) { edge_tile = tile_tl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), floor(tile_pos.y)))); }
if (tile_tr != tile) { edge_tile = tile_tr; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), floor(tile_pos.y)))); }
if (tile_br != tile) { edge_tile = tile_br; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), ceil(tile_pos.y)))); }
if (tile_bl != tile) { edge_tile = tile_bl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), ceil(tile_pos.y)))); }
if (tile_l != tile) { edge_tile = tile_l; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.x)); }
if (tile_r != tile) { edge_tile = tile_r; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.x)); }
if (tile_t != tile) { edge_tile = tile_t; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.y)); }
if (tile_b != tile) { edge_tile = tile_b; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.y)); }
if (tile == S_TileKind_Wall)
{
Vec4 outer = LinearFromSrgb(Vec4(0.05, 0.05, 0.05, 1));
Vec4 inner = LinearFromSrgb(Vec4(0.10, 0.10, 0.10, 1));
// result = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.375));
result = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.5));
}
else if (tile != S_TileKind_Empty)
{
SamplerState wrap_sampler = G_Dereference(params.pt_wrap_sampler);
SPR_Slice slice = params.tile_slices[tile];
Texture2D<Vec4> tile_tex = G_Dereference<Vec4>(slice.tex);
result = tile_tex.Sample(wrap_sampler, world_pos);
Vec4 floor_col = tile_tex.Sample(wrap_sampler, world_pos);
// if (edge_tile == S_TileKind_Wall && tile_edge_dist < 0.05)
// {
// // floor_col.rgb *= 0.25;
// }
result = floor_col;
}
else if (tile == S_TileKind_Wall)
{
// Distance to edge of wall in cells
f32 wall_dist = 0;
result = Color_Black;
// result.rgb *= wall_dist;
if (wall_dist > 1)
{
result = Color_White;
}
}
// switch (tile)
// {
@ -557,10 +523,18 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
Vec4 result = 0;
Vec2 world_pos = mul(params.xf.ui_to_world, Vec3(ui_pos, 1));
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
Vec2 tile_pos = mul(params.xf.world_to_tile, Vec3(world_pos, 1));
S_TileKind equipped_tile = params.equipped_tile;
f32 half_thickness = 1;
f32 half_bounds_size = S_WorldPitch * 0.5;
Vec2 bounds_screen_p0 = mul(params.xf.world_to_ui, Vec3(-half_bounds_size, -half_bounds_size, 1));
Vec2 bounds_screen_p1 = mul(params.xf.world_to_ui, Vec3(half_bounds_size, half_bounds_size, 1));
bool is_in_bounds = ui_pos.x > (bounds_screen_p0.x - half_thickness) &&
ui_pos.y > (bounds_screen_p0.y - half_thickness) &&
ui_pos.x < (bounds_screen_p1.x + half_thickness) &&
ui_pos.y < (bounds_screen_p1.y + half_thickness);
Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1));
// Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25));
@ -569,9 +543,9 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
Rng2 screen_selection = params.draw_selection;
Rng2 world_selection = params.world_selection;
Rng2I32 tile_selection;
tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0);
tile_selection.p1 = S_TilePosFromWorldPos(world_selection.p1);
Rng2 tile_selection;
tile_selection.p0 = floor(mul(params.xf.world_to_tile, Vec3(world_selection.p0, 1)));
tile_selection.p1 = ceil(mul(params.xf.world_to_tile, Vec3(world_selection.p1, 1)));
if (params.has_mouse_focus)
{
@ -607,6 +581,57 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
}
}
if (is_in_bounds)
{
// Grid outline
if (V_ShaderConst_GpuFlags & V_GpuFlag_DebugDraw)
{
const Vec4 grid_color = LinearFromSrgb(Vec4(1, 1, 1, 0.1));
Vec2 grid_screen_p0 = mul(params.xf.world_to_ui, Vec3(floor(world_pos), 1));
Vec2 grid_screen_p1 = mul(params.xf.world_to_ui, Vec3(ceil(world_pos), 1));
f32 grid_dist = 100000;
grid_dist = min(grid_dist, abs(ui_pos.x - grid_screen_p0.x));
grid_dist = min(grid_dist, abs(ui_pos.x - grid_screen_p1.x));
grid_dist = min(grid_dist, abs(ui_pos.y - grid_screen_p0.y));
grid_dist = min(grid_dist, abs(ui_pos.y - grid_screen_p1.y));
if (grid_dist <= half_thickness * 0.5)
{
result = grid_color;
}
}
// Axis
if (V_ShaderConst_GpuFlags & V_GpuFlag_DebugDraw)
{
const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1));
const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1));
Vec2 zero_screen = mul(params.xf.world_to_ui, Vec3(0, 0, 1));
f32 x_dist = abs(ui_pos.x - zero_screen.x);
f32 y_dist = abs(ui_pos.y - zero_screen.y);
if (y_dist <= half_thickness)
{
result = x_axis_color;
}
else if (x_dist <= half_thickness)
{
result = y_axis_color;
}
}
// World bounds
{
const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1));
f32 bounds_dist = 100000;
bounds_dist = min(bounds_dist, abs(ui_pos.x - bounds_screen_p0.x));
bounds_dist = min(bounds_dist, abs(ui_pos.x - bounds_screen_p1.x));
bounds_dist = min(bounds_dist, abs(ui_pos.y - bounds_screen_p0.y));
bounds_dist = min(bounds_dist, abs(ui_pos.y - bounds_screen_p1.y));
if (bounds_dist <= half_thickness)
{
result = bounds_color;
}
}
}
V_OverlayPSOutput output;
output.sv_target0 = result;
return output;

View File

@ -9,9 +9,16 @@
////////////////////////////////////////////////////////////
//~ Constant types
G_DeclConstant(G_RWStructuredBufferRef, V_ShaderConst_State, 0);
G_DeclConstant(G_StructuredBufferRef, V_ShaderConst_Params, 1);
G_DeclConstant(G_Texture3DRef, V_ShaderConst_NoiseTex, 2);
Enum(V_GpuFlag)
{
V_GpuFlag_None = 0,
V_GpuFlag_DebugDraw = (1 << 0),
};
G_DeclConstant(V_GpuFlag, V_ShaderConst_GpuFlags, 0);
G_DeclConstant(G_RWStructuredBufferRef, V_ShaderConst_State, 1);
G_DeclConstant(G_StructuredBufferRef, V_ShaderConst_Params, 2);
G_DeclConstant(G_Texture3DRef, V_ShaderConst_NoiseTex, 3);
Enum(V_SelectionMode)
{
@ -36,6 +43,10 @@ Struct(V_Xforms)
// World <-> cell
Xform world_to_cell;
Xform cell_to_world;
// World <-> tile
Xform world_to_tile;
Xform tile_to_world;
};
Struct(V_GpuState)