Add more methods for android, add platform class to abstract away some platform differences.

This commit is contained in:
UnknownShadow200 2016-01-07 22:29:40 +11:00
parent 99bd040d2f
commit 101cbc5f06
27 changed files with 300 additions and 488 deletions

View File

@ -3,6 +3,7 @@ using System;
using ClassicalSharp.GraphicsAPI;
using Android.Graphics;
using Android.Graphics.Drawables;
using System.Drawing;
namespace ClassicalSharp {
@ -11,7 +12,7 @@ namespace ClassicalSharp {
Bitmap measuringBmp;
Canvas measuringC;
public GdiPlusDrawer2D( IGraphicsApi graphics ) {
public CanvasDrawer2D( IGraphicsApi graphics ) {
this.graphics = graphics;
measuringBmp = Bitmap.CreateBitmap( 1, 1, Bitmap.Config.Argb8888 );
measuringC = new Canvas( measuringBmp );

View File

@ -21,6 +21,8 @@ namespace ClassicalSharp {
c = new Canvas( bmp );
curBmp = bmp;
}
public override Bitmap ConvertTo32Bpp( Bitmap src ) { return src; }
public override void DrawRect( FastColour colour, int x, int y, int width, int height ) {
RectF rec = new RectF( x, y, x + width, y + height );

View File

@ -1,4 +1,5 @@
using System;
#if !ANDROID
using System;
using System.Drawing;
using System.Drawing.Text;
using ClassicalSharp.GraphicsAPI;
@ -119,3 +120,4 @@ namespace ClassicalSharp {
}
}
}
#endif

View File

@ -1,4 +1,5 @@
using System;
#if !ANDROID
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
@ -102,3 +103,4 @@ namespace ClassicalSharp {
}
}
}
#endif

View File

@ -1,6 +1,9 @@
using System;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp {

View File

@ -2,6 +2,9 @@
using System.Collections.Generic;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp {
@ -140,7 +143,7 @@ namespace ClassicalSharp {
/// <summary> Creates a power-of-2 sized bitmap larger or equal to to the given size. </summary>
public static Bitmap CreatePow2Bitmap( Size size ) {
return new Bitmap( Utils.NextPowerOf2( size.Width ), Utils.NextPowerOf2( size.Height ) );
return Platform.CreateBmp( Utils.NextPowerOf2( size.Width ), Utils.NextPowerOf2( size.Height ) );
}
protected List<TextPart> parts = new List<TextPart>( 64 );

View File

@ -0,0 +1,143 @@
using System;
using ClassicalSharp.GraphicsAPI;
using ClassicalSharp.Model;
using OpenTK;
namespace ClassicalSharp {
public static class IsometricBlockDrawer {
static BlockInfo info;
static ModelCache cache;
static TerrainAtlas2D atlas;
static int index;
static float scale;
static Vector3 minBB, maxBB;
const float invElemSize = TerrainAtlas2D.invElementSize;
static bool fullBright;
static FastColour colNormal, colXSide, colZSide, colYBottom;
static float cosX, sinX, cosY, sinY;
static IsometricBlockDrawer() {
colNormal = FastColour.White;
FastColour.GetShaded( colNormal, ref colXSide, ref colZSide, ref colYBottom );
cosX = (float)Math.Cos( 26.565f * Utils.Deg2Rad );
sinX = (float)Math.Sin( 26.565f * Utils.Deg2Rad );
cosY = (float)Math.Cos( -45f * Utils.Deg2Rad );
sinY = (float)Math.Sin( -45f * Utils.Deg2Rad );
}
public static void Draw( Game game, byte block, float size, float x, float y ) {
info = game.BlockInfo;
cache = game.ModelCache;
atlas = game.TerrainAtlas;
minBB = info.MinBB[block];
maxBB = info.MaxBB[block];
fullBright = info.FullBright[block];
if( info.IsSprite[block] ) {
minBB = Vector3.Zero; maxBB = Vector3.One;
}
if( info.IsAir[block] ) return;
index = 0;
// isometric coords size: cosY * -scale - sinY * scale
// we need to divide by (2 * cosY), as the calling function expects size to be in pixels.
scale = size / (2 * cosY);
// screen to isometric coords (cos(-x) = cos(x), sin(-x) = -sin(x))
pos.X = x; pos.Y = y; pos.Z = 0;
pos = Utils.RotateY( Utils.RotateX( pos, cosX, -sinX ), cosY, -sinY );
if( info.IsSprite[block] ) {
XQuad( block, 0f, TileSide.Right );
ZQuad( block, 0f, TileSide.Back );
} else {
XQuad( block, Make( maxBB.X ), TileSide.Left );
ZQuad( block, Make( minBB.Z ), TileSide.Back );
YQuad( block, Make( maxBB.Y ), TileSide.Top );
}
for( int i = 0; i < index; i++ )
TransformVertex( ref cache.vertices[i] );
game.Graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, cache.vb,
cache.vertices, index, index * 6 / 4 );
}
static void TransformVertex( ref VertexPos3fTex2fCol4b vertex ) {
Vector3 p = new Vector3( vertex.X, vertex.Y, vertex.Z );
//p = Utils.RotateY( p - pos, time ) + pos;
// See comment in IGraphicsApi.Draw2DTexture()
p.X -= 0.5f; p.Y -= 0.5f;
p = Utils.RotateX( Utils.RotateY( p, cosY, sinY ), cosX, sinX );
vertex.X = p.X; vertex.Y = p.Y; vertex.Z = p.Z;
}
static Vector3 pos = Vector3.Zero;
static void YQuad( byte block, float y, int side ) {
int texId = info.GetTextureLoc( block, side );
TextureRec rec = atlas.GetTexRec( texId );
FastColour col = colNormal;
float uOrigin = rec.U1, vOrigin = rec.V1;
rec.U1 = uOrigin + minBB.Z * invElemSize;
rec.U2 = uOrigin + maxBB.Z * invElemSize * 15.99f/16f;
rec.V1 = vOrigin + minBB.X * invElemSize;
rec.V2 = vOrigin + maxBB.X * invElemSize * 15.99f/16f;
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + Make( minBB.X ), pos.Y + y,
pos.Z + Make( minBB.Z ), rec.U2, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + Make( minBB.X ), pos.Y + y,
pos.Z + Make( maxBB.Z ), rec.U1, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + Make( maxBB.X ), pos.Y + y,
pos.Z + Make( maxBB.Z ), rec.U1, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + Make( maxBB.X ), pos.Y + y,
pos.Z + Make( minBB.Z ), rec.U2, rec.V1, col );
}
static void ZQuad( byte block, float z, int side ) {
int texId = info.GetTextureLoc( block, side );
TextureRec rec = atlas.GetTexRec( texId );
FastColour col = fullBright ? colNormal : colZSide;
float uOrigin = rec.U1, vOrigin = rec.V1;
rec.U1 = uOrigin + minBB.X * invElemSize;
rec.U2 = uOrigin + maxBB.X * invElemSize * 15.99f/16f;
rec.V1 = vOrigin + (1 - maxBB.Y) * invElemSize;
rec.V2 = vOrigin + (1 - minBB.Y) * invElemSize;
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + Make( minBB.X ), pos.Y + Make( minBB.Y ),
pos.Z + z, rec.U2, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + Make( minBB.X ), pos.Y + Make( maxBB.Y ),
pos.Z + z, rec.U2, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + Make( maxBB.X ), pos.Y + Make( maxBB.Y ),
pos.Z + z, rec.U1, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + Make( maxBB.X ), pos.Y + Make( minBB.Y ),
pos.Z + z, rec.U1, rec.V2, col );
}
static float Make( float value ) {
return scale - (scale * value * 2);
}
static void XQuad( byte block, float x, int side ) {
int texId = info.GetTextureLoc( block, side );
TextureRec rec = atlas.GetTexRec( texId );
FastColour col = fullBright ? colNormal : colXSide;
float uOrigin = rec.U1, vOrigin = rec.V1;
rec.U1 = uOrigin + minBB.Z * invElemSize;
rec.U2 = uOrigin + maxBB.Z * invElemSize * 15.99f/16f;
rec.V1 = vOrigin + (1 - maxBB.Y) * invElemSize;
rec.V2 = vOrigin + (1 - minBB.Y) * invElemSize * 15.99f/16f;
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + Make( minBB.Y ),
pos.Z + Make( minBB.Z ), rec.U2, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + Make( maxBB.Y ),
pos.Z + Make( minBB.Z ), rec.U2, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + Make( maxBB.Y ),
pos.Z + Make( maxBB.Z ), rec.U1, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + Make( minBB.Y ),
pos.Z + Make( maxBB.Z ), rec.U1, rec.V2, col );
}
}
}

View File

@ -1,6 +1,10 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
#if ANDROID
using Android.Graphics;
using Java.Nio;
#endif
namespace ClassicalSharp {
@ -38,6 +42,24 @@ namespace ClassicalSharp {
return format == PixelFormat.Format32bppRgb || format == PixelFormat.Format32bppArgb;
}
/// <summary> Returns a pointer to the start of the y'th scanline. </summary>
public int* GetRowPtr( int y ) {
return (int*)(scan0Byte + (y * Stride));
}
public static void MovePortion( int srcX, int srcY, int dstX, int dstY, FastBitmap src, FastBitmap dst, int size ) {
for( int y = 0; y < size; y++ ) {
int* srcRow = src.GetRowPtr( srcY + y );
int* dstRow = dst.GetRowPtr( dstY + y );
for( int x = 0; x < size; x++ ) {
dstRow[dstX + x] = srcRow[srcX + x];
}
}
}
public void Dispose() { UnlockBits(); }
#if !ANDROID
public void LockBits() {
if( Bitmap == null ) throw new InvalidOperationException( "Underlying bitmap is null." );
if( data != null ) return;
@ -55,33 +77,43 @@ namespace ClassicalSharp {
Height = data.Height;
}
public void Dispose() {
UnlockBits();
public void UnlockBits() {
if( Bitmap == null || data == null )
return;
Bitmap.UnlockBits( data );
data = null;
scan0Byte = (byte*)IntPtr.Zero;
Scan0 = IntPtr.Zero;
Width = Height = Stride = 0;
}
#else
public void LockBits() {
if( Bitmap == null ) throw new InvalidOperationException( "Underlying bitmap is null." );
if( data != null ) return;
data = ByteBuffer.AllocateDirect( Bitmap.Width * Bitmap.Height * 4 );
Bitmap.CopyPixelsToBuffer( data );
scan0Byte = (byte*)data.GetDirectBufferAddress();
Scan0 = data.GetDirectBufferAddress();
Stride = Bitmap.Width * 4;
Width = Bitmap.Width;
Height = Bitmap.Height;
}
public void UnlockBits() {
if( Bitmap != null && data != null ) {
Bitmap.UnlockBits( data );
data = null;
scan0Byte = (byte*)IntPtr.Zero;
Scan0 = IntPtr.Zero;
Width = Height = Stride = 0;
}
}
/// <summary> Returns a pointer to the start of the y'th scanline. </summary>
public int* GetRowPtr( int y ) {
return (int*)(scan0Byte + (y * Stride));
}
public static void MovePortion( int srcX, int srcY, int dstX, int dstY, FastBitmap src, FastBitmap dst, int size ) {
for( int y = 0; y < size; y++ ) {
int* srcRow = src.GetRowPtr( srcY + y );
int* dstRow = dst.GetRowPtr( dstY + y );
for( int x = 0; x < size; x++ ) {
dstRow[dstX + x] = srcRow[srcX + x];
}
}
if( Bitmap == null || data == null )
return;
data.Rewind();
Bitmap.CopyPixelsFromBuffer( data ); // TODO: Only if not readonly
data.Dispose();
data = null;
scan0Byte = (byte*)IntPtr.Zero;
Scan0 = IntPtr.Zero;
Width = Height = Stride = 0;
}
#endif
}
}

View File

@ -1,128 +0,0 @@
using System;
using ClassicalSharp.GraphicsAPI;
using ClassicalSharp.Model;
using OpenTK;
namespace ClassicalSharp {
public static class IsometricBlockDrawer {
static BlockInfo info;
static ModelCache cache;
static TerrainAtlas2D atlas;
static float blockHeight;
static int index;
static float scale;
static Vector3 minBB, maxBB;
static FastColour colNormal, colXSide, colZSide, colYBottom;
static float cosX, sinX, cosY, sinY;
static IsometricBlockDrawer() {
colNormal = FastColour.White;
FastColour.GetShaded( colNormal, ref colXSide, ref colZSide, ref colYBottom );
cosX = (float)Math.Cos( 26.565f * Utils.Deg2Rad );
sinX = (float)Math.Sin( 26.565f * Utils.Deg2Rad );
cosY = (float)Math.Cos( -45f * Utils.Deg2Rad );
sinY = (float)Math.Sin( -45f * Utils.Deg2Rad );
}
public static void Draw( Game game, byte block, float size, float x, float y ) {
info = game.BlockInfo;
cache = game.ModelCache;
atlas = game.TerrainAtlas;
minBB = info.MinBB[block];
maxBB = info.MaxBB[block];
blockHeight = info.Height[block];
index = 0;
// isometric coords size: cosY * -scale - sinY * scale
// we need to divide by (2 * cosY), as the calling function expects size to be in pixels.
scale = size / (2 * cosY);
// screen to isometric coords (cos(-x) = cos(x), sin(-x) = -sin(x))
pos.X = x; pos.Y = y; pos.Z = 0;
pos = Utils.RotateY( Utils.RotateX( pos, cosX, -sinX ), cosY, -sinY );
if( info.IsSprite[block] ) {
XQuad( block, 0f, TileSide.Right );
ZQuad( block, 0f, TileSide.Back );
} else {
XQuad( block, scale, TileSide.Left );
ZQuad( block, -scale, TileSide.Back );
YQuad( block, Y( maxBB.Y ), TileSide.Top );
}
for( int i = 0; i < index; i++ )
TransformVertex( ref cache.vertices[i] );
game.Graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, cache.vb,
cache.vertices, index, index * 6 / 4 );
}
static void TransformVertex( ref VertexPos3fTex2fCol4b vertex ) {
Vector3 p = new Vector3( vertex.X, vertex.Y, vertex.Z );
//p = Utils.RotateY( p - pos, time ) + pos;
// See comment in IGraphicsApi.Draw2DTexture()
p.X -= 0.5f; p.Y -= 0.5f;
p = Utils.RotateX( Utils.RotateY( p, cosY, sinY ), cosX, sinX );
vertex.X = p.X; vertex.Y = p.Y; vertex.Z = p.Z;
}
static Vector3 pos = Vector3.Zero;
static void YQuad( byte block, float y, int side ) {
int texId = info.GetTextureLoc( block, side );
TextureRec rec = atlas.GetTexRec( texId );
FastColour col = colNormal;
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y - y,
pos.Z - scale, rec.U2, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y - y,
pos.Z + scale, rec.U1, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y - y,
pos.Z + scale, rec.U1, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y - y,
pos.Z - scale, rec.U2, rec.V1, col );
}
static void ZQuad( byte block, float z, int side ) {
int texId = info.GetTextureLoc( block, side );
TextureRec rec = atlas.GetTexRec( texId );
FastColour col = colZSide;
float vOrigin = rec.V1;
rec.V1 = vOrigin + minBB.Y * TerrainAtlas2D.invElementSize;
rec.V2 = vOrigin + maxBB.Y * TerrainAtlas2D.invElementSize;
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y + Y( minBB.Y ),
pos.Z - z, rec.U1, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y + Y( maxBB.Y ),
pos.Z - z, rec.U1, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y + Y( maxBB.Y ),
pos.Z - z, rec.U2, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y + Y( minBB.Y ),
pos.Z - z, rec.U2, rec.V1, col );
}
static float Y( float value ) {
return (scale * value * 2) - scale;
}
static void XQuad( byte block, float x, int side ) {
int texId = info.GetTextureLoc( block, side );
TextureRec rec = atlas.GetTexRec( texId );
FastColour col = colXSide;
float vOrigin = rec.V1;
rec.V1 = vOrigin + minBB.Y * TerrainAtlas2D.invElementSize;
rec.V2 = vOrigin + maxBB.Y * TerrainAtlas2D.invElementSize;
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + Y( minBB.Y ),
pos.Z - scale , rec.U1, rec.V1, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + Y( maxBB.Y ),
pos.Z - scale, rec.U1, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + Y( maxBB.Y ),
pos.Z + scale, rec.U2, rec.V2, col );
cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - x, pos.Y + Y( minBB.Y ),
pos.Z + scale, rec.U2, rec.V1, col );
}
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp {

View File

@ -1,84 +0,0 @@
#if ANDROID
using System;
using Android.Graphics;
using Java.Nio;
namespace ClassicalSharp {
/// <summary> Wrapper around a bitmap that allows extremely fast manipulation of 32bpp images. </summary>
public unsafe class FastBitmap : IDisposable {
public FastBitmap( Bitmap bmp, bool lockBits ) {
Bitmap = bmp;
if( lockBits ) {
LockBits();
}
}
public FastBitmap( int width, int height, int stride, IntPtr scan0 ) {
Width = width;
Height = height;
Stride = stride;
Scan0 = scan0;
scan0Byte = (byte*)scan0;
}
public Bitmap Bitmap;
ByteBuffer data;
byte* scan0Byte;
public bool IsLocked {
get { return data != null; }
}
public IntPtr Scan0;
public int Stride;
public int Width, Height;
public void LockBits() {
if( Bitmap == null ) throw new InvalidOperationException( "Underlying bitmap is null." );
if( data != null ) return;
data = ByteBuffer.AllocateDirect( Bitmap.Width * Bitmap.Height * 4 );
Bitmap.CopyPixelsToBuffer( data );
scan0Byte = (byte*)data.GetDirectBufferAddress();
Scan0 = data.GetDirectBufferAddress();
Stride = Bitmap.Width * 4;
Width = Bitmap.Width;
Height = Bitmap.Height;
}
public void Dispose() {
UnlockBits();
}
public void UnlockBits() {
if( Bitmap != null && data != null ) {
data.Rewind();
Bitmap.CopyPixelsFromBuffer( data ); // TODO: Only if not readonly
data.Dispose();
data = null;
scan0Byte = (byte*)IntPtr.Zero;
Scan0 = IntPtr.Zero;
Width = Height = Stride = 0;
}
}
/// <summary> Returns a pointer to the start of the y'th scanline. </summary>
public int* GetRowPtr( int y ) {
return (int*)(scan0Byte + (y * Stride));
}
public static void MovePortion( int srcX, int srcY, int dstX, int dstY, FastBitmap src, FastBitmap dst, int size ) {
for( int y = 0; y < size; y++ ) {
int* srcRow = src.GetRowPtr( srcY + y );
int* dstRow = dst.GetRowPtr( dstY + y );
for( int x = 0; x < size; x++ ) {
dstRow[dstX + x] = srcRow[srcX + x];
}
}
}
}
}
#endif

View File

@ -1,221 +0,0 @@
#if ANDROID
using System;
namespace System.Drawing {
public struct Rectangle {
public static readonly Rectangle Empty = default(Rectangle);
public int X, Y;
public int Width, Height;
public Point Location {
get { return new Point( X, Y ); }
set { X = value.X; Y = value.Y; }
}
public Size Size {
get { return new Size( Width, Height ); }
set { Width = value.Width; Height = value.Height; }
}
public int Left {
get { return X; }
}
public int Top {
get { return Y; }
}
public int Right {
get { return X + Width; }
}
public int Bottom {
get { return Y + Height; }
}
public bool IsEmpty {
get { return Height == 0 && Width == 0 && X == 0 && Y == 0; }
}
public Rectangle( int x, int y, int width, int height ) {
X = x; Y = y;
Width = width; Height = height;
}
public Rectangle( Point loc, Size size ) {
X = loc.X; Y = loc.Y;
Width = size.Width; Height = size.Height;
}
public static Rectangle FromLTRB( int left, int top, int right, int bottom ) {
return new Rectangle( left, top, right - left, bottom - top );
}
public override bool Equals( object obj ) {
return (obj is Rectangle) && Equals( (Rectangle)obj );
}
public bool Equals( Rectangle other ) {
return X == other.X && Y == other.Y && Width == other.Width && Height == other.Height;
}
public override int GetHashCode() {
return 1000000007 * X + 1000000009 * Y +
1000000021 * Width + 1000000033 * Height;
}
public static bool operator == ( Rectangle lhs, Rectangle rhs ) {
return lhs.Equals( rhs );
}
public static bool operator != ( Rectangle lhs, Rectangle rhs ) {
return !(lhs == rhs);
}
public bool Contains(int x, int y) {
return X <= x && x < X + Width && Y <= y && y < Y + Height;
}
public bool Contains( Point pt ) {
return Contains( pt.X, pt.Y );
}
public bool Contains( Rectangle rect ) {
return X <= rect.X && rect.X + rect.Width <= X + Width && Y <= rect.Y && rect.Y + rect.Height <= Y + Height;
}
public override string ToString() {
return X + ", " + Y + " : " + Width + "," + Height;
}
}
public struct Size {
public static readonly Size Empty = default(Size);
public int Width, Height;
public bool IsEmpty {
get { return Width == 0 && Height == 0; }
}
public Size( Point point ) {
Width = point.X; Height = point.Y;
}
public Size( int width, int height ) {
Width = width; Height = height;
}
public static Size Ceiling( SizeF value ) {
return new Size( (int)Math.Ceiling( value.Width ), (int)Math.Ceiling( value.Height ) );
}
public override bool Equals( object obj ) {
return (obj is Size) && Equals( (Size)obj );
}
public bool Equals( Size other ) {
return Width == other.Width && Height == other.Height;
}
public override int GetHashCode() {
return 1000000007 * Width + 1000000009 * Height;
}
public static bool operator == ( Size lhs, Size rhs ) {
return lhs.Width == rhs.Width && lhs.Height == rhs.Height;
}
public static bool operator != ( Size lhs, Size rhs ) {
return !(lhs == rhs);
}
public override string ToString() {
return Width + "," + Height;
}
}
public struct SizeF {
public static readonly SizeF Empty = default(SizeF);
public float Width, Height;
public bool IsEmpty {
get { return Width == 0 && Height == 0; }
}
public SizeF( float width, float height ) {
Width = width; Height = height;
}
public override bool Equals( object obj ) {
return (obj is SizeF) && Equals( (SizeF)obj );
}
public bool Equals( SizeF other ) {
return Width == other.Width && Height == other.Height;
}
public override int GetHashCode() {
return 1000000007 * Width.GetHashCode() +
1000000009 * Height.GetHashCode();
}
public static bool operator == ( SizeF lhs, SizeF rhs ) {
return lhs.Width == rhs.Width && lhs.Height == rhs.Height;
}
public static bool operator != ( SizeF lhs, SizeF rhs ) {
return !(lhs == rhs);
}
public override string ToString() {
return Width + "," + Height;
}
}
public struct Point {
public static readonly Point Empty = default(Point);
public int X, Y;
public bool IsEmpty {
get { return X == 0 && Y == 0; }
}
public Point( Size size ) {
X = size.Width; Y = size.Height;
}
public Point( int x, int y ) {
X = x; Y = y;
}
public override bool Equals( object obj ) {
return (obj is Point) && Equals( (Point)obj );
}
public bool Equals( Point other ) {
return X == other.X && Y == other.Y;
}
public override int GetHashCode() {
return 1000000007 * X + 1000000009 * Y;
}
public static bool operator == ( Point lhs, Point rhs ) {
return lhs.X == rhs.X && lhs.Y == rhs.Y;
}
public static bool operator != ( Point lhs, Point rhs ) {
return !(lhs == rhs);
}
public override string ToString() {
return X + "," + Y;
}
}
}
#endif

View File

@ -78,6 +78,8 @@
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="2D\Drawing\CanvasDrawer2D.cs" />
<Compile Include="2D\Drawing\CanvasDrawer2D.Text.cs" />
<Compile Include="2D\Drawing\GdiPlusDrawer2D.Text.cs" />
<Compile Include="2D\Drawing\IDrawer2D.TextMC.cs" />
<Compile Include="2D\GuiElement.cs" />
@ -130,12 +132,6 @@
<Compile Include="2D\Widgets\PlayerListWidget.cs" />
<Compile Include="2D\Widgets\TextWidget.cs" />
<Compile Include="2D\Widgets\Widget.cs" />
<Compile Include="Android\CanvasDrawer2D.cs" />
<Compile Include="Android\CanvasDrawer2D.Text.cs" />
<Compile Include="Android\FastBitmap.cs" />
<Compile Include="Android\Font.cs" />
<Compile Include="Android\Minimal.cs" />
<Compile Include="Android\OpenGLESApi.cs" />
<Compile Include="Audio\AudioPlayer.cs" />
<Compile Include="Audio\AudioPlayer.Sounds.cs" />
<Compile Include="Audio\Soundboard.cs" />
@ -161,6 +157,7 @@
<Compile Include="Generator\Noise.cs" />
<Compile Include="Generator\NotchyGenerator.cs" />
<Compile Include="Generator\NotchyGenerator.Utils.cs" />
<Compile Include="GraphicsAPI\OpenGLESApi.cs" />
<Compile Include="Particles\CollidableParticle.cs" />
<Compile Include="Particles\Particle.cs" />
<Compile Include="Particles\ParticleManager.cs" />
@ -225,6 +222,8 @@
<Compile Include="Physics\IntersectionUtils.cs" />
<Compile Include="Physics\PickedPos.cs" />
<Compile Include="Physics\Picking.cs" />
<Compile Include="Platform\Font.cs" />
<Compile Include="Platform\Platform.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Rendering\BlockHandRenderer.cs" />
@ -286,7 +285,7 @@
<Folder Include="Blocks" />
<Folder Include="Events" />
<Folder Include="Generator" />
<Folder Include="Android" />
<Folder Include="Platform" />
<Folder Include="Particles" />
<Folder Include="GraphicsAPI" />
<Folder Include="Entities" />

View File

@ -3,6 +3,9 @@ using System.Drawing;
using ClassicalSharp.Model;
using ClassicalSharp.Network;
using OpenTK;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp {

View File

@ -15,6 +15,9 @@ using ClassicalSharp.TexturePack;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp {
@ -279,7 +282,7 @@ namespace ClassicalSharp {
string timestamp = DateTime.Now.ToString( "dd-MM-yyyy-HH-mm-ss" );
string file = "screenshot_" + timestamp + ".png";
path = Path.Combine( "screenshots", file );
Graphics.TakeScreenshot( path, ClientSize );
Graphics.TakeScreenshot( path, ClientSize.Width, ClientSize.Height );
Chat.Add( "&eTaken screenshot as: " + file );
screenshotRequested = false;
}

View File

@ -1,4 +1,4 @@
#if USE_DX
#if USE_DX && !ANDROID
using System;
using System.Drawing;
using System.Drawing.Imaging;
@ -562,14 +562,14 @@ namespace ClassicalSharp.GraphicsAPI {
};
}
public override void TakeScreenshot( string output, Size size ) {
public override void TakeScreenshot( string output, int width, int height ) {
using( Surface backbuffer = device.GetBackBuffer( 0, 0, BackBufferType.Mono ),
tempSurface = device.CreateOffscreenPlainSurface( size.Width, size.Height, Format.X8R8G8B8, Pool.SystemMemory ) ) {
tempSurface = device.CreateOffscreenPlainSurface( width, height, Format.X8R8G8B8, Pool.SystemMemory ) ) {
// For DX 8 use IDirect3DDevice8::CreateImageSurface
device.GetRenderTargetData( backbuffer, tempSurface );
LockedRectangle rect = tempSurface.LockRectangle( LockFlags.ReadOnly | LockFlags.NoDirtyUpdate );
using( Bitmap bmp = new Bitmap( size.Width, size.Height, size.Width * 4,
using( Bitmap bmp = new Bitmap( width, height, width * sizeof(int),
PixelFormat.Format32bppRgb, rect.DataPointer ) ) {
bmp.Save( output, ImageFormat.Png );
}

View File

@ -202,7 +202,7 @@ namespace ClassicalSharp.GraphicsAPI {
public abstract void PopMatrix();
/// <summary> Outputs a .png screenshot of the backbuffer to the specified file. </summary>
public abstract void TakeScreenshot( string output, Size size );
public abstract void TakeScreenshot( string output, int width, int height );
protected abstract void MakeApiInfo();

View File

@ -1,4 +1,4 @@
#if !USE_DX
#if !USE_DX && !ANDROID
using System;
using System.Drawing;
using System.Drawing.Imaging;
@ -405,11 +405,10 @@ namespace ClassicalSharp.GraphicsAPI {
}
// Based on http://www.opentk.com/doc/graphics/save-opengl-rendering-to-disk
public override void TakeScreenshot( string output, Size size ) {
using( Bitmap bmp = new Bitmap( size.Width, size.Height, BmpPixelFormat.Format32bppRgb ) ) { // ignore alpha component
using( FastBitmap fastBmp = new FastBitmap( bmp, true ) ) {
GL.ReadPixels( 0, 0, size.Width, size.Height, GlPixelFormat.Bgra, PixelType.UnsignedByte, fastBmp.Scan0 );
}
public override void TakeScreenshot( string output, int width, int height ) {
using( Bitmap bmp = new Bitmap( width, height, BmpPixelFormat.Format32bppRgb ) ) { // ignore alpha component
using( FastBitmap fastBmp = new FastBitmap( bmp, true ) )
GL.ReadPixels( 0, 0, width, height, GlPixelFormat.Bgra, PixelType.UnsignedByte, fastBmp.Scan0 );
bmp.RotateFlip( RotateFlipType.RotateNoneFlipY );
bmp.Save( output, ImageFormat.Png );
}

View File

@ -12,7 +12,7 @@ namespace ClassicalSharp.GraphicsAPI {
public unsafe class OpenGLESApi : IGraphicsApi {
All[] modeMappings;
public OpenGLApi() {
public OpenGLESApi() {
InitFields();
int texDims;
GL.GetInteger( All.MaxTextureSize, &texDims );

View File

@ -196,7 +196,7 @@ namespace ClassicalSharp.Network {
object DownloadContent( Request request, HttpWebResponse response ) {
if( request.Type == RequestType.Bitmap ) {
MemoryStream data = DownloadBytes( response );
return new Bitmap( data );
return Platform.ReadBmp( data );
} else if( request.Type == RequestType.String ) {
MemoryStream data = DownloadBytes( response );
byte[] rawBuffer = data.GetBuffer();

View File

@ -0,0 +1,38 @@
using System;
using System.Drawing;
using System.IO;
#if ANDROID
using Android.Graphics;
#else
using System.Drawing.Imaging;
#endif
namespace ClassicalSharp {
public static class Platform {
public static Bitmap CreateBmp( int width, int height ) {
#if !ANDROID
return new Bitmap( width, height );
#else
return Bitmap.CreateBitmap( width, height, Bitmap.Config.Argb8888 );
#endif
}
public static Bitmap ReadBmp( Stream src ) {
#if !ANDROID
return new Bitmap( src );
#else
return BitmapFactory.DecodeStream( src );
#endif
}
public static void WriteBmp( Bitmap bmp, Stream dst ) {
#if !ANDROID
bmp.Save( dst, ImageFormat.Png );
#else
bmp.Compress( Bitmap.CompressFormat.Png, 100, dst );
#endif
}
}
}

View File

@ -3,6 +3,9 @@ using System.Collections.Generic;
using System.Drawing;
using System.IO;
using ClassicalSharp.GraphicsAPI;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp.TexturePack {

View File

@ -1,6 +1,9 @@
using System;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp {

View File

@ -3,6 +3,9 @@ using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp.TexturePack {
@ -63,7 +66,8 @@ namespace ClassicalSharp.TexturePack {
if( !Directory.Exists( basePath ) )
Directory.CreateDirectory( basePath );
bmp.Save( path, ImageFormat.Png );
using( FileStream fs = File.Create( path ) )
Platform.WriteBmp( bmp, fs );
} catch( IOException ex ) {
ErrorHandler.LogError( "Cache.AddToCache", ex );
}

View File

@ -39,7 +39,7 @@ namespace ClassicalSharp.TexturePack {
IGraphicsApi api = game.Graphics;
switch( filename ) {
case "terrain.png":
game.ChangeTerrainAtlas( new Bitmap( stream ) ); break;
game.ChangeTerrainAtlas( Platform.ReadBmp( stream ) ); break;
case "mob/chicken.png":
case "chicken.png":
UpdateTexture( ref cache.ChickenTexId, stream, false ); break;
@ -79,7 +79,7 @@ namespace ClassicalSharp.TexturePack {
UpdateTexture( ref game.GuiClassicTexId, stream, false ); break;
case "animations.png":
case "animation.png":
game.Animations.SetAtlas( new Bitmap( stream ) ); break;
game.Animations.SetAtlas( Platform.ReadBmp( stream ) ); break;
case "animations.txt":
case "animation.txt":
StreamReader reader = new StreamReader( stream );
@ -95,14 +95,14 @@ namespace ClassicalSharp.TexturePack {
}
void SetFontBitmap( Game game, Stream stream ) {
Bitmap bmp = new Bitmap( stream );
Bitmap bmp = Platform.ReadBmp( stream );
game.Drawer2D.SetFontBitmap( bmp );
game.Events.RaiseChatFontChanged();
}
void UpdateTexture( ref int texId, Stream stream, bool setSkinType ) {
game.Graphics.DeleteTexture( ref texId );
using( Bitmap bmp = new Bitmap( stream ) ) {
using( Bitmap bmp = Platform.ReadBmp( stream ) ) {
if( setSkinType )
game.DefaultPlayerSkinType = Utils.GetSkinType( bmp );

View File

@ -2,6 +2,9 @@
using System.Drawing;
using OpenTK;
using OpenTK.Input;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp {