////TODO: pass state ptr *NOT* value ptr (it's confusing) // We don't allow custom default values for state so all zeros indicates // default states for us. // NOTE: The given argument should point directly to the value *not* to the // base state to which the state block offset has to be added. internal unsafe bool CheckStateIsAllZeros(IntPtr valuePtr = new IntPtr()) { if (valuePtr == IntPtr.Zero) { valuePtr = new IntPtr(currentStatePtr.ToInt64() + (int)m_StateBlock.byteOffset); } // Bitfield value. if (m_StateBlock.sizeInBits % 8 != 0 || m_StateBlock.bitOffset != 0) { if (m_StateBlock.sizeInBits > 1) { throw new NotImplementedException("multi-bit zero check"); } return(BitfieldHelpers.ReadSingleBit(valuePtr, m_StateBlock.bitOffset) == false); } // Multi-byte value. var ptr = (byte *)valuePtr; var numBytes = m_StateBlock.alignedSizeInBytes; for (var i = 0; i < numBytes; ++i, ++ptr) { if (*ptr != 0) { return(false); } } return(true); }
public KeyboardState(params Key[] pressedKeys) { fixed(byte *keysPtr = keys) { UnsafeUtility.MemClear(new IntPtr(keysPtr), kSizeInBytes); for (var i = 0; i < pressedKeys.Length; ++i) { BitfieldHelpers.WriteSingleBit(new IntPtr(keysPtr), (uint)pressedKeys[i], true); } } }
private unsafe string ReadRawValueAsString(InputControl control) { fixed(byte *state = stateBuffer) { var ptr = state + control.m_StateBlock.byteOffset - m_RootControl.m_StateBlock.byteOffset; var format = control.m_StateBlock.format; if (format == InputStateBlock.kTypeBit) { if (BitfieldHelpers.ReadSingleBit(new IntPtr(ptr), control.m_StateBlock.bitOffset)) { return("1"); } return("0"); } if (format == InputStateBlock.kTypeByte) { return((*ptr).ToString()); } if (format == InputStateBlock.kTypeShort) { return((*((short *)ptr)).ToString()); } if (format == InputStateBlock.kTypeInt) { return((*((int *)ptr)).ToString()); } if (format == InputStateBlock.kTypeFloat) { return((*((float *)ptr)).ToString()); } if (format == InputStateBlock.kTypeDouble) { return((*((double *)ptr)).ToString()); } return(null); } }
// Read a floating-point value from the given state. Automatically checks // the state format of the control and performs conversions. // NOTE: Throws if the format set on 'stateBlock' is not of integer, floating-point, // or bitfield type. protected override unsafe float ReadRawValueFrom(IntPtr statePtr) { float value; var valuePtr = new IntPtr(statePtr.ToInt64() + (int)m_StateBlock.byteOffset); var format = m_StateBlock.format; if (format == InputStateBlock.kTypeFloat) { value = *(float *)valuePtr; } else if (format == InputStateBlock.kTypeBit) { if (m_StateBlock.sizeInBits != 1) { throw new NotImplementedException("Cannot yet convert multi-bit fields to floats"); } value = BitfieldHelpers.ReadSingleBit(valuePtr, m_StateBlock.bitOffset) ? 1.0f : 0.0f; } // If a control with an integer-based representation does not use the full range // of its integer size (e.g. only goes from [0..128]), processors or the parameters // above have to be used to re-process the resulting float values. else if (format == InputStateBlock.kTypeShort) { value = *((short *)valuePtr) / 65535.0f; } else if (format == InputStateBlock.kTypeByte) { value = *((byte *)valuePtr) / 255.0f; } else { throw new Exception(string.Format("State format '{0}' is not supported as state for {1}", m_StateBlock.format, GetType().Name)); } return(Preprocess(value)); }
private static void ComputeStateLayout(InputControl control) { var children = control.m_ChildrenReadOnly; // 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 Exception( string.Format( "Control '{0}' with template '{1}' has no size set but has no children to compute size from", control.path, control.template)); } // 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); // 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) { throw new Exception( string.Format("Child '{0}' of '{1}' has no size set!", child.name, control.name)); } // Skip children that don't have fixed offsets. if (child.m_StateBlock.byteOffset == InputStateBlock.kInvalidOffset) { continue; } var endOffset = BitfieldHelpers.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.kInvalidOffset) { 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.kInvalidOffset) { bitfieldSizeInBits += child.m_StateBlock.sizeInBits; } else { 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 = BitfieldHelpers.ComputeFollowingByteOffset(runningByteOffset, bitfieldSizeInBits); firstBitAddressingChild = null; } } child.m_StateBlock.byteOffset = runningByteOffset; if (!isBitAddressingChild) { runningByteOffset = BitfieldHelpers.ComputeFollowingByteOffset(runningByteOffset, child.m_StateBlock.sizeInBits); } } // Compute total size. // If we ended on a bitfield, account for its size. if (firstBitAddressingChild != null) { runningByteOffset = BitfieldHelpers.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; }