private static void SetFormat(InputControl control, InputControlLayout.ControlItem controlItem) { control.m_StateBlock.format = controlItem.format; if (controlItem.sizeInBits == 0) { var primitiveFormatSize = InputStateBlock.GetSizeOfPrimitiveFormatInBits(controlItem.format); if (primitiveFormatSize != -1) { control.m_StateBlock.sizeInBits = (uint)primitiveFormatSize; } } }
private static void SetFormat(InputControl control, InputTemplate.ControlTemplate controlTemplate) { control.m_StateBlock.format = controlTemplate.format; if (controlTemplate.sizeInBits == 0) { var primitiveFormatSize = InputStateBlock.GetSizeOfPrimitiveFormatInBits(controlTemplate.format); if (primitiveFormatSize != -1) { control.m_StateBlock.sizeInBits = (uint)primitiveFormatSize; } } }
private static void ComputeStateLayout(InputControl control) { var children = control.children; // If the control has a format but no size specified and the format is a // primitive format, just set the size automatically. if (control.m_StateBlock.sizeInBits == 0 && control.m_StateBlock.format != 0) { var sizeInBits = InputStateBlock.GetSizeOfPrimitiveFormatInBits(control.m_StateBlock.format); if (sizeInBits != -1) { control.m_StateBlock.sizeInBits = (uint)sizeInBits; } } // If state size is not set, it means it's computed from the size of the // children so make sure we actually have children. if (control.m_StateBlock.sizeInBits == 0 && children.Count == 0) { throw new InvalidOperationException( $"Control '{control.path}' with layout '{control.layout}' has no size set and has no children to compute size from"); } // If there's no children, our job is done. if (children.Count == 0) { return; } // First deal with children that want fixed offsets. All the other ones // will get appended to the end. var firstUnfixedByteOffset = 0u; foreach (var child in children) { Debug.Assert(child.m_StateBlock.sizeInBits != 0, "Size of state block not set on child"); // Skip children using state from other controls. if (child.m_StateBlock.sizeInBits == kSizeForControlUsingStateFromOtherControl) { continue; } // Make sure the child has a valid size set on it. var childSizeInBits = child.m_StateBlock.sizeInBits; if (childSizeInBits == 0 || childSizeInBits == InputStateBlock.InvalidOffset) { throw new InvalidOperationException( $"Child '{child.name}' of '{control.name}' has no size set!"); } // Skip children that don't have fixed offsets. if (child.m_StateBlock.byteOffset == InputStateBlock.InvalidOffset || child.m_StateBlock.byteOffset == InputStateBlock.AutomaticOffset) { continue; } // At this point, if the child has no valid bit offset, put it at #0 now. if (child.m_StateBlock.bitOffset == InputStateBlock.InvalidOffset) { child.m_StateBlock.bitOffset = 0; } // See if the control bumps our fixed layout size. var endOffset = MemoryHelpers.ComputeFollowingByteOffset(child.m_StateBlock.byteOffset, child.m_StateBlock.bitOffset + childSizeInBits); if (endOffset > firstUnfixedByteOffset) { firstUnfixedByteOffset = endOffset; } } ////TODO: this doesn't support mixed automatic and fixed layouting *within* bitfields; //// I think it's okay not to support that but we should at least detect it // Now assign an offset to every control that wants an // automatic offset. For bitfields, we need to delay advancing byte // offsets until we've seen all bits in the fields. // NOTE: Bit addressing controls using automatic offsets *must* be consecutive. var runningByteOffset = firstUnfixedByteOffset; InputControl firstBitAddressingChild = null; var bitfieldSizeInBits = 0u; foreach (var child in children) { // Skip children with fixed offsets. if (child.m_StateBlock.byteOffset != InputStateBlock.InvalidOffset && child.m_StateBlock.byteOffset != InputStateBlock.AutomaticOffset) { continue; } // Skip children using state from other controls. if (child.m_StateBlock.sizeInBits == kSizeForControlUsingStateFromOtherControl) { continue; } // See if it's a bit addressing control. var isBitAddressingChild = (child.m_StateBlock.sizeInBits % 8) != 0; if (isBitAddressingChild) { // Remember start of bitfield group. if (firstBitAddressingChild == null) { firstBitAddressingChild = child; } // Keep a running count of the size of the bitfield. if (child.m_StateBlock.bitOffset == InputStateBlock.InvalidOffset || child.m_StateBlock.bitOffset == InputStateBlock.AutomaticOffset) { // Put child at current bit offset. child.m_StateBlock.bitOffset = bitfieldSizeInBits; bitfieldSizeInBits += child.m_StateBlock.sizeInBits; } else { // Child already has bit offset. Keep it but make sure we're accounting for it // in the bitfield size. var lastBit = child.m_StateBlock.bitOffset + child.m_StateBlock.sizeInBits; if (lastBit > bitfieldSizeInBits) { bitfieldSizeInBits = lastBit; } } } else { // Terminate bitfield group (if there was one). if (firstBitAddressingChild != null) { runningByteOffset = MemoryHelpers.ComputeFollowingByteOffset(runningByteOffset, bitfieldSizeInBits); firstBitAddressingChild = null; } if (child.m_StateBlock.bitOffset == InputStateBlock.InvalidOffset) { child.m_StateBlock.bitOffset = 0; } } ////FIXME: seems like this should take bitOffset into account child.m_StateBlock.byteOffset = runningByteOffset; if (!isBitAddressingChild) { runningByteOffset = MemoryHelpers.ComputeFollowingByteOffset(runningByteOffset, child.m_StateBlock.sizeInBits); } } // Compute total size. // If we ended on a bitfield, account for its size. if (firstBitAddressingChild != null) { runningByteOffset = MemoryHelpers.ComputeFollowingByteOffset(runningByteOffset, bitfieldSizeInBits); } var totalSizeInBytes = runningByteOffset; // Set size. We force all parents to the combined size of their children. control.m_StateBlock.sizeInBits = totalSizeInBytes * 8; }