using System.Collections.Generic; using StereoKit; namespace snake; static class Arts { static Model assets_model = Model.FromFile("meshes/assets.glb", Shader.Unlit); static Dictionary meshes = new(); static Material mat_mono = new Material("mono.hlsl"); static Material mat_unlit = new Material("unlit.hlsl"); static Material mat_box = new Material("unlit.hlsl"); static Material mat_backbox = new Material("backbox.hlsl"); static Material mat_justcolor = new Material("justcolor.hlsl"); public static Vec3 box_shake = new(0, 0, 0); static Quat food_ori = Quat.Identity; static XYZi last_headpos = new(0, 0, 0); static DeltaBool headmove = new(false); static XYZi last_tailpos = new(0, 0, 0); static DeltaBool tailmove = new(false); static TextStyle text_style; public static void Init() { foreach (ModelNode node in assets_model.Nodes) { if (node.Mesh != null) { meshes.Add(node.Name, node.Mesh); } } text_style = TextStyle.FromFont( Font.FromFile("Staatliches.ttf"), 1.0f * U.cm, Color.White ); mat_backbox.FaceCull = Cull.Front; mat_backbox.Transparency = Transparency.Add; mat_backbox.DepthTest = DepthTest.LessOrEq; mat_backbox.DepthWrite = false; mat_box.Chain = mat_backbox; } public static void Frame() { bool vr = Device.DisplayBlend == DisplayBlend.Opaque; // render hands if not in mixed reality Input.HandVisible(Handed.Max, false); if (vr) { // background standin if no passthrough } // fullstick Mesh.Sphere.Draw( mat_unlit, Matrix.TS( Rig.r_con_stick.position, 5 * U.mm ), Color.White ); Lines.Add( Rig.r_con_stick.position + V.XYZ(0, 0, 0), Rig.r_con_stick.position + Rig.fullstick * 1.5f * U.cm, Color.White, 2 * U.mm ); // box box_shake = Vec3.Lerp(box_shake, Vec3.Zero, Time.Stepf / 0.333f); // scale in float box_scale = Mono.box_scale; // Maths.min(Maths.smooth_stop(Maths.u_scalar(Time.Totalf - 3)) * Mono.box_scale, Mono.box_scale); Vec3 box_pos = Mono.box_pose.position + (box_shake * U.cm * 0.333f); Matrix box_m4 = Matrix.TRS( box_pos, Mono.box_pose.orientation, box_scale ); // telescoping hanging rod if (Mono.in_cone.state && Mono.box_mode == Mono.BoxMode.Hold || Mono.box_mode == Mono.BoxMode.Mount) { float box_head_dist = Vec3.Distance(box_pos, Rig.head.position); Vec3 box_mount = box_m4 * V.XYZ(0, Mono.SD_Y - 0.5f, 0); Vec3 box_handl = Rig.head.position + Rig.head.orientation * V.XYZ(0, 6 * U.cm, -box_head_dist); Vec3 head_mount = Rig.head.position + Rig.head.orientation * V.XYZ(0, 6 * U.cm, 0); Vec3 head_handl = Vec3.Lerp(box_handl, head_mount, 0.5f); Vec3[] p = new Vec3[] { box_mount, box_handl, head_handl, head_mount, }; // debug bezier points // for (int i = 0; i < p.Length; i++) // { // Mesh.Sphere.Draw( // mat_justcolor, // Matrix.TS( // p[i], // 2 * U.mm // ), // Color.White // ); // } Mesh.Sphere.Draw( mat_justcolor, Matrix.TS( box_mount, 3 * U.mm ), Color.Hex(0x959493FF).ToLinear() ); int steps = 64; Vec3 pastPos = p[0]; float pastThc = 0.0f; for (int i = 0; i < steps; i++) { float t = (float)i / (steps - 1); Vec3 a = Vec3.Lerp(p[0], p[1], t); Vec3 b = Vec3.Lerp(p[1], p[2], t); Vec3 c = Vec3.Lerp(p[2], p[3], t); Vec3 pos = Vec3.Lerp(Vec3.Lerp(a, b, t), Vec3.Lerp(b, c, t), t); float thc = (1.0f + Maths.precision(t, 0.333f) * 2.0f) * U.mm; Lines.Add( pastPos, pos, thc != pastThc ? Color.Hex(0x959493FF).ToLinear() : Color.Hex(0x808080FF).ToLinear(), thc ); pastPos = pos; pastThc = thc; } } // box contents Hierarchy.Push(box_m4); // meshes["InsideOut"].Draw(mat_unlit, Matrix.Identity); meshes["InsideOut"].Draw( mat_box, Matrix.Identity ); meshes["Corrugation"].Draw( Mono.in_dist.state ? mat_justcolor : mat_unlit, Matrix.Identity ); if (Mono.menu) { meshes["Tape"].Draw(mat_mono, Matrix.Identity); meshes["uiRestart"].Draw( mat_unlit, Matrix.TR( V.XYZ(-1.333f, 0, Mono.SD_Z - 0.5f + 0.1f), Quat.FromAngles(90, 0, 0) ), Color.Hex(0x928CA7FF).ToLinear() ); meshes["uiPlay"].Draw( mat_unlit, Matrix.TR( V.XYZ(0, 0, Mono.SD_Z - 0.5f + 0.1f), Quat.FromAngles(90, 0, 0) ), Color.Hex(0x333333FF).ToLinear() ); meshes["uiConfig"].Draw( mat_unlit, Matrix.TR( V.XYZ(+1.333f, 0, Mono.SD_Z - 0.5f + 0.1f), Quat.FromAngles(90, 0, 0) ), Color.Hex(0x928CA7FF).ToLinear() ); meshes["uiCursor"].Draw( mat_unlit, Matrix.TR( V.XYZ(0, 0, Mono.SD_Z - 0.5f + 0.2f), Quat.FromAngles(90, 0, 0) ) ); } // snake float snake_t = headmove.state ? Maths.u_clamp(Maths.smooth_stop((float)Mono.step_t) * 3.0f) : 1.0f; if (!Mono.menu && !Mono.food_next.state) { meshes["Tongue"].Draw( mat_mono, Matrix.TRS( Mono.snake[0].ToVec3, Quat.LookDir(Rig.fullstick), V.XYZ(1, 1, 0.666f + Maths.smooth_stop((float)Mono.step_t) * 0.333f) ) ); } string face = "Face0Default"; face = Mono.grow_buffer > 0 ? "Face2Eaten" : face; face = Mono.in_box.delta != 0 ? "Face3Bump" : face; face = Mono.food_next.state ? "Face1Eat" : face; meshes[face].Draw( mat_mono, Matrix.TRS( Mono.snake[0].ToVec3 - (Mono.snake_dir.ToVec3 * (float)(1.0 - snake_t) * 0.3f), Quat.LookDir(Mono.snake_dir.ToVec3), V.XYZ(1, 1, (float)(snake_t)) ) ); for (int i = 1; i < Mono.snake_len; i++) { float scale = 1.0f; if ((int)((Time.Total - Mono.eat_timestamp) * Mono.snake_len / Mono.step_step) == i) { scale = 1.1f; } meshes["Segment"].Draw( mat_mono, Matrix.TRS( Mono.snake[i].ToVec3, Quat.LookAt(Mono.snake[i].ToVec3, Mono.snake[i - 1].ToVec3), scale ) ); } // false tail if (tailmove.state && snake_t < 1.0f) { int i_tail = Maths.min(Mono.snake_len, Mono.snake.Length - 1); Vec3 tail_dir = Vec3.Direction(Mono.snake[i_tail - 1].ToVec3, Mono.snake[i_tail].ToVec3); meshes["Segment"].Draw( mat_mono, Matrix.TRS( Mono.snake[i_tail].ToVec3 + (tail_dir * (float)(snake_t) * 0.7f), Quat.LookDir(tail_dir), V.XYZ(1, 1, (float)(1.0 - snake_t)) ) ); } // holes foreach (KeyValuePair hole in Mono.holes) { Vec3 hole_normal = V.XYZ( Maths.abs(hole.Value.x) * Maths.sign(hole.Key.x), Maths.abs(hole.Value.y) * Maths.sign(hole.Key.y), Maths.abs(hole.Value.z) * Maths.sign(hole.Key.z) ); // Vec3 hole_world_normal = Mono.box_pose.orientation * hole_normal; // Vec3 hole_world = Mono.box_pose.ToMatrix(Mono.box_scale) * V.XYZ( // hole.Key.x - hole.Value.x * 0.5f, // hole.Key.y - hole.Value.y * 0.5f, // hole.Key.z - hole.Value.z * 0.5f // ); // Vec3 cam_dir = (Rig.head.orientation * Vec3.Forward); // Vec3 hole_view_dir = Vec3.Direction(hole_world, Rig.head.position); // bool back_hole = Vec3.Dot(hole_world_normal, hole_view_dir) < 0.0; bool hole_flip = Vec3.Dot(hole_normal, hole.Value.ToVec3) < 0.0; meshes[hole_flip ? "Hole" : "HoleFlip"].Draw( mat_box, Matrix.TRS( hole.Key.ToVec3, Quat.LookDir(hole.Value.ToVec3), 1 ) ); } // food if (!Mono.food_next.state) { food_ori *= Quat.FromAngles( 90 * Time.Stepf, 30 * Time.Stepf, 10 * Time.Stepf ); } if (Mono.eaten == 0) { // starting egg bool in_snake = Mono.s_array[new XYZi(0, 0, 0)] > -1; meshes["Egg"].Draw( mat_mono, Matrix.TRS( Vec3.Zero, in_snake ? Quat.Identity : food_ori, in_snake ? 1 : 0.5f ) ); } else { // food if (!Mono.eaten_latch.state) { float food_t = Mono.eaten_latch.delta == -1 ? Maths.smooth_stop((float)Mono.step_t) : 1; meshes["Food"].Draw( mat_mono, Matrix.TRS( Mono.food.ToVec3, food_ori, food_t ) ); } } // particles Particle[] particles = VFX.particles; for (int i = 0; i < particles.Length; i++) { Particle particle = particles[i]; meshes["FoodParticle"].Draw( mat_mono, Matrix.TRS( particle.pos, particle.ori, particle.scl ) ); } // score char[] score_txt = Mono.snake_len.ToString("000").ToCharArray(); Quat score_ori = Quat.LookDir(Rig.head.position - Mono.box_pose.position); Vec3 score_pos = score_ori * V.XYZ(0, -Mono.SD_Y - 1.5f, -Mono.SD_Z - 1); for (int i = 0; i < score_txt.Length; i++) { Text.Add( score_txt[i].ToString(), Matrix.TRS( score_pos + score_ori * V.XYZ((1 - i) * 0.4f, 0, 0), score_ori, 48 ), text_style ); } Hierarchy.Pop(); // for (int sx = -Mono.head_fill.Xslen; Mono.head_fill.InX(sx); sx++) // { // for (int sy = -Mono.head_fill.Yslen; Mono.head_fill.InY(sy); sy++) // { // for (int sz = -Mono.head_fill.Zslen; Mono.head_fill.InZ(sz); sz++) // { // Vec3 pos = Mono.box_pose.ToMatrix(U.cm) * V.XYZ(sx, sy, sz); // Text.Add( // (Mono.head_fill[new XYZi(sx, sy, sz)] + Mono.tail_fill[new XYZi(sx, sy, sz)]).ToString(), // Matrix.TRS( // pos, // Quat.LookAt(pos, Input.Head.position), // 0.1f // ) // ); // } // } // } } public static void Step() { XYZi snake_head = Mono.snake[0]; XYZi snake_tail = Mono.snake[Mono.snake_len - 1]; headmove.Step(snake_head != last_headpos); tailmove.Step(snake_tail != last_tailpos); last_headpos = snake_head; last_tailpos = snake_tail; } }