mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-13 09:35:23 -04:00
Proper fix of UnsafeString on windows platforms - should fix input text and block info string.
This commit is contained in:
parent
f33428a531
commit
c163ebcb59
@ -28,7 +28,7 @@ namespace ClassicalSharp {
|
||||
int rows;
|
||||
int startX, startY;
|
||||
readonly Font font;
|
||||
UnsafeString buffer = new UnsafeString( 96 );
|
||||
StringBuffer buffer = new StringBuffer( 96 );
|
||||
|
||||
public override void Render( double delta ) {
|
||||
graphicsApi.Texturing = true;
|
||||
@ -130,9 +130,7 @@ namespace ClassicalSharp {
|
||||
|
||||
Block block = blocksTable[selectedIndex].BlockId;
|
||||
UpdateBlockInfoString( block );
|
||||
string value = buffer.value;
|
||||
if( Utils2D.needWinXpFix )
|
||||
value = value.TrimEnd( Utils2D.trimChars );
|
||||
string value = buffer.UpdateCachedString();
|
||||
|
||||
Size size = Utils2D.MeasureSize( value, font, true );
|
||||
int x = startX + ( blockSize * blocksPerRow ) / 2 - size.Width / 2;
|
||||
|
@ -6,10 +6,10 @@ namespace ClassicalSharp {
|
||||
public class FpsScreen : Screen {
|
||||
|
||||
readonly Font font;
|
||||
UnsafeString text;
|
||||
StringBuffer text;
|
||||
public FpsScreen( Game window ) : base( window ) {
|
||||
font = new Font( "Arial", 13 );
|
||||
text = new UnsafeString( 96 );
|
||||
text = new StringBuffer( 96 );
|
||||
}
|
||||
|
||||
TextWidget fpsTextWidget;
|
||||
@ -37,10 +37,8 @@ namespace ClassicalSharp {
|
||||
.Append( ref ptr2, "), chunks/s: " ).AppendNum( ref ptr2, game.ChunkUpdates )
|
||||
.Append( ref ptr2, ", vertices: " ).AppendNum( ref ptr2, game.Vertices );
|
||||
}
|
||||
string textString = text.value;
|
||||
if( Utils2D.needWinXpFix )
|
||||
textString = textString.TrimEnd( Utils2D.trimChars );
|
||||
|
||||
string textString = text.UpdateCachedString();
|
||||
fpsTextWidget.SetText( textString );
|
||||
maxDelta = 0;
|
||||
accumulator = 0;
|
||||
|
@ -12,8 +12,6 @@ namespace ClassicalSharp {
|
||||
static Bitmap measuringBmp;
|
||||
static Graphics measuringGraphics;
|
||||
static Dictionary<int, SolidBrush> brushCache = new Dictionary<int, SolidBrush>( 16 );
|
||||
internal static bool needWinXpFix;
|
||||
internal static char[] trimChars = { '\0' };
|
||||
|
||||
static Utils2D() {
|
||||
format = StringFormat.GenericTypographic;
|
||||
@ -24,8 +22,6 @@ namespace ClassicalSharp {
|
||||
measuringBmp = new Bitmap( 1, 1 );
|
||||
measuringGraphics = Graphics.FromImage( measuringBmp );
|
||||
measuringGraphics.TextRenderingHint = TextRenderingHint.AntiAlias;
|
||||
OperatingSystem os = Environment.OSVersion;
|
||||
needWinXpFix = os.Platform == PlatformID.Win32NT && os.Version.Major < 6;
|
||||
}
|
||||
|
||||
static SolidBrush GetOrCreateBrush( Color color ) {
|
||||
|
@ -19,7 +19,7 @@ namespace ClassicalSharp {
|
||||
typingLogPos = game.ChatInputLog.Count; // Index of newest entry + 1.
|
||||
this.font = font;
|
||||
this.boldFont = boldFont;
|
||||
chatInputText = new UnsafeString( 64 );
|
||||
chatInputText = new StringBuffer( 64 );
|
||||
}
|
||||
|
||||
Texture chatInputTexture, chatCaretTexture;
|
||||
@ -27,7 +27,7 @@ namespace ClassicalSharp {
|
||||
int caretPos = -1;
|
||||
int typingLogPos = 0;
|
||||
public int ChatInputYOffset;
|
||||
internal UnsafeString chatInputText;
|
||||
internal StringBuffer chatInputText;
|
||||
readonly Font font, boldFont;
|
||||
|
||||
public override void Render( double delta ) {
|
||||
@ -40,9 +40,7 @@ namespace ClassicalSharp {
|
||||
X = 10;
|
||||
DrawTextArgs caretArgs = new DrawTextArgs( graphicsApi, "_", Color.White, false );
|
||||
chatCaretTexture = Utils2D.MakeTextTexture( boldFont, 0, 0, ref caretArgs );
|
||||
string value = chatInputText.value;
|
||||
if( Utils2D.needWinXpFix )
|
||||
value = value.TrimEnd( Utils2D.trimChars );
|
||||
string value = chatInputText.UpdateCachedString();
|
||||
|
||||
if( chatInputText.Empty ) {
|
||||
caretPos = -1;
|
||||
@ -53,9 +51,12 @@ namespace ClassicalSharp {
|
||||
chatCaretTexture.X1 = 10 + size.Width;
|
||||
size.Width += chatCaretTexture.Width;
|
||||
} else {
|
||||
Size trimmedSize = Utils2D.MeasureSize( value.Substring( 0, caretPos ), font, false );
|
||||
string subString = chatInputText.GetSubstring( caretPos );
|
||||
Size trimmedSize = Utils2D.MeasureSize( subString, font, false );
|
||||
chatInputText.RestoreLength();
|
||||
|
||||
chatCaretTexture.X1 = 10 + trimmedSize.Width;
|
||||
Size charSize = Utils2D.MeasureSize( value.Substring( caretPos, 1 ), font, false );
|
||||
Size charSize = Utils2D.MeasureSize( new String( value[caretPos], 1 ), font, false );
|
||||
chatCaretTexture.Width = charSize.Width;
|
||||
}
|
||||
size.Height = Math.Max( size.Height, chatCaretTexture.Height );
|
||||
|
@ -164,7 +164,7 @@
|
||||
<Compile Include="Utils\TerrainAtlas1D.cs" />
|
||||
<Compile Include="Utils\TerrainAtlas2D.cs" />
|
||||
<Compile Include="Utils\TextureRectangle.cs" />
|
||||
<Compile Include="Utils\UnsafeString.cs" />
|
||||
<Compile Include="Utils\StringBuffer.cs" />
|
||||
<Compile Include="Utils\Utils.cs" />
|
||||
<Compile Include="Utils\Vector3I.cs" />
|
||||
</ItemGroup>
|
||||
|
180
ClassicalSharp/Utils/StringBuffer.cs
Normal file
180
ClassicalSharp/Utils/StringBuffer.cs
Normal file
@ -0,0 +1,180 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ClassicalSharp {
|
||||
|
||||
// Class used to minimise memory allocations of strings.
|
||||
// Really, only useful for FpsScreen and TextInputWidget as they allocate lots of very small strings.
|
||||
// Seriously, you should *not* use this anywhere else, as Empty and Length are O(N).
|
||||
internal sealed unsafe class StringBuffer {
|
||||
|
||||
internal string value;
|
||||
internal int capacity;
|
||||
|
||||
static readonly FieldInfo arrayField, lengthField;
|
||||
static bool supportsLengthSetting;
|
||||
|
||||
static StringBuffer() {
|
||||
if( OpenTK.Configuration.RunningOnMono )
|
||||
return;
|
||||
|
||||
arrayField = typeof( String ).GetField( "m_arrayLength", BindingFlags.NonPublic | BindingFlags.Instance );
|
||||
lengthField = typeof( String ).GetField( "m_stringLength", BindingFlags.NonPublic | BindingFlags.Instance );
|
||||
|
||||
// Make sure we are running on a framework that has both methods -
|
||||
// otherwise we play it safe and just use TrimEnd().
|
||||
if( arrayField != null && lengthField != null ) {
|
||||
supportsLengthSetting = true;
|
||||
} else {
|
||||
arrayField = null;
|
||||
lengthField = null;
|
||||
}
|
||||
}
|
||||
|
||||
public StringBuffer( int capacity ) {
|
||||
this.capacity = capacity;
|
||||
value = new String( '\0', capacity );
|
||||
}
|
||||
|
||||
public StringBuffer Append( int index, char c ) {
|
||||
fixed( char* ptr = value ) {
|
||||
ptr[index] = c;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public StringBuffer Append( int index, string s ) {
|
||||
fixed( char* ptr = value ) {
|
||||
char* offsetPtr = ptr + index;
|
||||
return Append( ref offsetPtr, s );
|
||||
}
|
||||
}
|
||||
|
||||
public StringBuffer Append( ref char* ptr, string s ) {
|
||||
for( int i = 0; i < s.Length; i++ ) {
|
||||
*ptr++ = s[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public StringBuffer Append( ref char* ptr, char c) {
|
||||
*ptr++ = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
static char[] numBuffer = new char[20];
|
||||
public StringBuffer AppendNum( ref char* ptr, long num ) {
|
||||
int index = 0;
|
||||
numBuffer[index++] = (char)( '0' + ( num % 10 ) );
|
||||
num /= 10;
|
||||
|
||||
while( num > 0 ) {
|
||||
numBuffer[index++] = (char)( '0' + ( num % 10 ) );
|
||||
num /= 10;
|
||||
}
|
||||
for( int i = index - 1; i >= 0; i-- ) {
|
||||
*ptr++ = numBuffer[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public StringBuffer Clear() {
|
||||
fixed( char* ptr = value ) {
|
||||
return Clear( ptr );
|
||||
}
|
||||
}
|
||||
|
||||
public StringBuffer Clear( char* ptr ) {
|
||||
for( int i = 0; i < capacity; i++ ) {
|
||||
*ptr++ = '\0';
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void DeleteAt( int index ) {
|
||||
fixed( char* ptr = value ) {
|
||||
char* offsetPtr = ptr + index;
|
||||
for( int i = index; i < capacity - 1; i++ ) {
|
||||
*offsetPtr = *( offsetPtr + 1 );
|
||||
offsetPtr++;
|
||||
}
|
||||
*offsetPtr = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertAt( int index, char c ) {
|
||||
fixed( char* ptr = value ) {
|
||||
char* offsetPtr = ptr + capacity - 1;
|
||||
for( int i = capacity - 1; i > index; i-- ) {
|
||||
*offsetPtr = *( offsetPtr - 1 );
|
||||
offsetPtr--;
|
||||
}
|
||||
*offsetPtr = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool Empty {
|
||||
get {
|
||||
fixed( char* ptr = value ) {
|
||||
for( int i = 0; i < capacity; i++ ) {
|
||||
if( ptr[i] != '\0' )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int Length {
|
||||
get {
|
||||
int len = capacity;
|
||||
fixed( char* ptr = value ) {
|
||||
for( int i = capacity - 1; i >= 0; i-- ) {
|
||||
if( ptr[i] != '\0' )
|
||||
break;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Hack that modifies the underlying string's length to avoid memory allocations. </summary>
|
||||
/// <returns> The underlying string - ***do not*** store this because it is mutable!
|
||||
/// You should only use this string for temporary measuring and drawing. </returns>
|
||||
public string UpdateCachedString() {
|
||||
return supportsLengthSetting ? value : value.TrimEnd( trimEnd );
|
||||
}
|
||||
static char[] trimEnd = { '\0' };
|
||||
|
||||
public override string ToString() {
|
||||
return GetCopy( Length );
|
||||
}
|
||||
|
||||
public string GetSubstring( int length ) {
|
||||
return supportsLengthSetting ? SetLength( length ) : GetCopy( length );
|
||||
}
|
||||
|
||||
public void RestoreLength() {
|
||||
if( supportsLengthSetting )
|
||||
SetLength( Length );
|
||||
}
|
||||
|
||||
string SetLength( int len ) {
|
||||
arrayField.SetValue( value, len + 1 );
|
||||
lengthField.SetValue( value, len );
|
||||
return value;
|
||||
}
|
||||
|
||||
string GetCopy( int len ) {
|
||||
string copiedString = new String( '\0', len );
|
||||
fixed( char* src = value, dst = copiedString ) {
|
||||
for( int i = 0; i < len; i++ ) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
return copiedString;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ClassicalSharp {
|
||||
|
||||
// Class used to minimise memory allocations of strings.
|
||||
// Really, only useful for FpsScreen and TextInputWidget as they allocate lots of very small strings.
|
||||
// Seriously, you should *not* use this anywhere else, as Empty and Length are O(N).
|
||||
internal sealed unsafe class UnsafeString {
|
||||
|
||||
internal string value;
|
||||
internal int capacity;
|
||||
|
||||
public UnsafeString( int capacity ) {
|
||||
this.capacity = capacity;
|
||||
value = new String( '\0', capacity );
|
||||
}
|
||||
|
||||
public UnsafeString Append( int index, char c ) {
|
||||
fixed( char* ptr = value ) {
|
||||
ptr[index] = c;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public UnsafeString Append( int index, string s ) {
|
||||
fixed( char* ptr = value ) {
|
||||
char* offsetPtr = ptr + index;
|
||||
return Append( ref offsetPtr, s );
|
||||
}
|
||||
}
|
||||
|
||||
public UnsafeString Append( ref char* ptr, string s ) {
|
||||
for( int i = 0; i < s.Length; i++ ) {
|
||||
*ptr++ = s[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public UnsafeString Append( ref char* ptr, char c) {
|
||||
*ptr++ = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
static char[] numBuffer = new char[20];
|
||||
public UnsafeString AppendNum( ref char* ptr, long num ) {
|
||||
int index = 0;
|
||||
numBuffer[index++] = (char)( '0' + ( num % 10 ) );
|
||||
num /= 10;
|
||||
|
||||
while( num > 0 ) {
|
||||
numBuffer[index++] = (char)( '0' + ( num % 10 ) );
|
||||
num /= 10;
|
||||
}
|
||||
for( int i = index - 1; i >= 0; i-- ) {
|
||||
*ptr++ = numBuffer[i];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public UnsafeString Clear() {
|
||||
fixed( char* ptr = value ) {
|
||||
return Clear( ptr );
|
||||
}
|
||||
}
|
||||
|
||||
public UnsafeString Clear( char* ptr ) {
|
||||
for( int i = 0; i < capacity; i++ ) {
|
||||
*ptr++ = '\0';
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void DeleteAt( int index ) {
|
||||
fixed( char* ptr = value ) {
|
||||
char* offsetPtr = ptr + index;
|
||||
for( int i = index; i < capacity - 1; i++ ) {
|
||||
*offsetPtr = *( offsetPtr + 1 );
|
||||
offsetPtr++;
|
||||
}
|
||||
*offsetPtr = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertAt( int index, char c ) {
|
||||
fixed( char* ptr = value ) {
|
||||
char* offsetPtr = ptr + capacity - 1;
|
||||
for( int i = capacity - 1; i > index; i-- ) {
|
||||
*offsetPtr = *( offsetPtr - 1 );
|
||||
offsetPtr--;
|
||||
}
|
||||
*offsetPtr = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool Empty {
|
||||
get {
|
||||
for( int i = 0; i < capacity; i++ ) {
|
||||
if( value[i] != '\0' )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int Length {
|
||||
get {
|
||||
int len = capacity;
|
||||
for( int i = capacity - 1; i >= 0; i-- ) {
|
||||
if( value[i] != '\0' )
|
||||
break;
|
||||
len--;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return value.TrimEnd( '\0' );
|
||||
}
|
||||
}
|
||||
}
|
@ -113,7 +113,7 @@ namespace SharpDX.Direct3D9 {
|
||||
return lockedRect;
|
||||
}
|
||||
|
||||
public void SetData( int level, LockFlags flags, IntPtr data,int bytes ) {
|
||||
public void SetData( int level, LockFlags flags, IntPtr data, int bytes ) {
|
||||
LockedRectangle rect = LockRectangle( level, flags );
|
||||
MemUtils.memcpy( data, rect.DataPointer, bytes );
|
||||
UnlockRectangle( level );
|
||||
|
Loading…
x
Reference in New Issue
Block a user