Various fixes and improvements
This commit is contained in:
parent
803415c988
commit
f9a8376b93
@ -45,6 +45,10 @@
|
|||||||
*.Input.Touch.TouchLocationState
|
*.Input.Touch.TouchLocationState
|
||||||
*.Input.Touch.TouchPanel
|
*.Input.Touch.TouchPanel
|
||||||
*.Input.Touch.TouchPanelCapabilities
|
*.Input.Touch.TouchPanelCapabilities
|
||||||
|
*.Input.Keyboard
|
||||||
|
*.Input.KeyboardState
|
||||||
|
*.Input.Keys
|
||||||
|
*.Input.KeyState
|
||||||
|
|
||||||
*.Graphics.BasicEffect
|
*.Graphics.BasicEffect
|
||||||
*.Graphics.Blend
|
*.Graphics.Blend
|
||||||
|
@ -11,11 +11,45 @@ namespace Microsoft.Xna.Framework
|
|||||||
|
|
||||||
protected override void onCreate(android.os.Bundle savedInstanceState)
|
protected override void onCreate(android.os.Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
|
// on some devices, this should be before call to base.onCreate
|
||||||
|
// requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
|
||||||
|
|
||||||
|
logTag = GetMetaAttr_Str("log.tag", "BNA_Game");
|
||||||
|
|
||||||
|
backKeyCode = GetMetaAttr_Int("back.key");
|
||||||
|
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= 19)
|
||||||
|
{
|
||||||
|
immersiveMode = GetMetaAttr_Int("immersive.mode") != 0;
|
||||||
|
|
||||||
|
if (immersiveMode && android.os.Build.VERSION.SDK_INT >= 28)
|
||||||
|
{
|
||||||
|
var layoutParams = getWindow().getAttributes();
|
||||||
|
layoutParams.layoutInDisplayCutoutMode =
|
||||||
|
android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||||
|
getWindow().setAttributes(layoutParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetMetaAttr_Int("keep.screen.on") != 0)
|
||||||
|
{
|
||||||
|
getWindow().addFlags(
|
||||||
|
android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int flags = android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||||
|
| android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
|
||||||
|
| android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||||
|
| android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
||||||
|
if (GetMetaAttr_Int("keep.screen.on") != 0)
|
||||||
|
flags |= android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
|
||||||
|
getWindow().setFlags(flags
|
||||||
|
| android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
|
||||||
|
flags);
|
||||||
|
*/
|
||||||
|
|
||||||
base.onCreate(savedInstanceState);
|
base.onCreate(savedInstanceState);
|
||||||
|
|
||||||
_LogTag = GetMetaAttr("log.tag") ?? _LogTag;
|
|
||||||
|
|
||||||
new java.lang.Thread(gameRunner = new GameRunner(this)).start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -36,7 +70,7 @@ namespace Microsoft.Xna.Framework
|
|||||||
|
|
||||||
//
|
//
|
||||||
// Android events forwarded to GameRunner:
|
// Android events forwarded to GameRunner:
|
||||||
// onPause, onResume, onDestroy, onTouchEvent
|
// onPause, onWindowFocusChanged, onDestroy, onTouchEvent, onBackPressed
|
||||||
//
|
//
|
||||||
|
|
||||||
protected override void onPause()
|
protected override void onPause()
|
||||||
@ -45,11 +79,39 @@ namespace Microsoft.Xna.Framework
|
|||||||
base.onPause();
|
base.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void onResume()
|
public override void onWindowFocusChanged(bool hasFocus)
|
||||||
|
{
|
||||||
|
base.onWindowFocusChanged(hasFocus);
|
||||||
|
|
||||||
|
if (hasFocus)
|
||||||
|
{
|
||||||
|
if (immersiveMode)
|
||||||
|
{
|
||||||
|
getWindow().getDecorView().setSystemUiVisibility(
|
||||||
|
android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||||
|
| android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||||
|
| android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||||
|
| android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||||
|
| android.view.View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||||
|
| android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.ReferenceEquals(gameRunner, null))
|
||||||
|
{
|
||||||
|
new java.lang.Thread(gameRunner = new GameRunner(this)).start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gameRunner.ActivityResume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*protected override void onResume()
|
||||||
{
|
{
|
||||||
gameRunner?.ActivityResume();
|
gameRunner?.ActivityResume();
|
||||||
base.onResume();
|
base.onResume();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
protected override void onDestroy()
|
protected override void onDestroy()
|
||||||
{
|
{
|
||||||
@ -79,33 +141,47 @@ namespace Microsoft.Xna.Framework
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void onBackPressed()
|
||||||
|
{
|
||||||
|
if (backKeyCode != 0)
|
||||||
|
gameRunner?.ActivityKey(backKeyCode);
|
||||||
|
else
|
||||||
|
base.onBackPressed();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// GetMetaAttr
|
// GetMetaAttr_Str, GetMetaAttr_Int
|
||||||
//
|
//
|
||||||
|
|
||||||
public string GetMetaAttr(string name, bool warn = false)
|
public string GetMetaAttr_Str(string name, string def)
|
||||||
{
|
{
|
||||||
var info = getPackageManager().getActivityInfo(getComponentName(),
|
name = "BNA." + name;
|
||||||
android.content.pm.PackageManager.GET_ACTIVITIES
|
var str = GetMetaData()?.getString(name);
|
||||||
| android.content.pm.PackageManager.GET_META_DATA);
|
|
||||||
name = "microsoft.xna.framework." + name;
|
|
||||||
var str = info?.metaData?.getString(name);
|
|
||||||
if (string.IsNullOrEmpty(str))
|
if (string.IsNullOrEmpty(str))
|
||||||
{
|
{
|
||||||
if (warn)
|
Activity.Log($"missing metadata attribute '{name}'");
|
||||||
Activity.Log($"missing metadata attribute '{name}'");
|
str = def;
|
||||||
str = null;
|
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetMetaAttr_Int(string name)
|
||||||
|
=> GetMetaData()?.getInt("BNA." + name) ?? 0;
|
||||||
|
|
||||||
|
private android.os.Bundle GetMetaData()
|
||||||
|
=> getPackageManager().getActivityInfo(
|
||||||
|
getComponentName(),
|
||||||
|
android.content.pm.PackageManager.GET_ACTIVITIES
|
||||||
|
| android.content.pm.PackageManager.GET_META_DATA)
|
||||||
|
?.metaData;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Log
|
// Log
|
||||||
//
|
//
|
||||||
|
|
||||||
public static void Log(string s) => android.util.Log.i(_LogTag, s);
|
public static void Log(string s) => android.util.Log.i(logTag, s);
|
||||||
|
|
||||||
private static string _LogTag = "BNA_Game";
|
private static string logTag;
|
||||||
|
|
||||||
//
|
//
|
||||||
// data
|
// data
|
||||||
@ -113,6 +189,8 @@ namespace Microsoft.Xna.Framework
|
|||||||
|
|
||||||
private GameRunner gameRunner;
|
private GameRunner gameRunner;
|
||||||
private bool restartActivity;
|
private bool restartActivity;
|
||||||
|
private bool immersiveMode;
|
||||||
|
private int backKeyCode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
BNA/src/Debug.cs
Normal file
13
BNA/src/Debug.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
namespace System.Diagnostics
|
||||||
|
{
|
||||||
|
|
||||||
|
public static class Debug
|
||||||
|
{
|
||||||
|
public static void WriteLine(string message)
|
||||||
|
{
|
||||||
|
Microsoft.Xna.Framework.GameRunner.Log(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -67,7 +67,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
public string CreateProgram2(string vertexText, string fragmentText)
|
public string CreateProgram2(string vertexText, string fragmentText)
|
||||||
{
|
{
|
||||||
string errText = null;
|
string errText = null;
|
||||||
Renderer.Get(GraphicsDevice.GLDevice).Send( () =>
|
Renderer.Get(GraphicsDevice.GLDevice).Send(true, () =>
|
||||||
{
|
{
|
||||||
(vertexId, errText) = CompileShader(
|
(vertexId, errText) = CompileShader(
|
||||||
GLES20.GL_VERTEX_SHADER, "vertex", vertexText);
|
GLES20.GL_VERTEX_SHADER, "vertex", vertexText);
|
||||||
@ -93,7 +93,6 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
|
|
||||||
(int, string) CompileShader(int kind, string errKind, string text)
|
(int, string) CompileShader(int kind, string errKind, string text)
|
||||||
{
|
{
|
||||||
//GameRunner.Log($"SHADER PROGRAM: [[[" + text + "]]]");
|
|
||||||
string errText = null;
|
string errText = null;
|
||||||
int shaderId = GLES20.glCreateShader(kind);
|
int shaderId = GLES20.glCreateShader(kind);
|
||||||
int errCode = GLES20.glGetError();
|
int errCode = GLES20.glGetError();
|
||||||
@ -237,7 +236,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
public (string name, int type, int size)[] GetProgramUniforms()
|
public (string name, int type, int size)[] GetProgramUniforms()
|
||||||
{
|
{
|
||||||
(string, int, int)[] result = null;
|
(string, int, int)[] result = null;
|
||||||
Renderer.Get(GraphicsDevice.GLDevice).Send( () =>
|
Renderer.Get(GraphicsDevice.GLDevice).Send(true, () =>
|
||||||
{
|
{
|
||||||
var count = new int[1];
|
var count = new int[1];
|
||||||
GLES20.glGetProgramiv(programId, GLES20.GL_ACTIVE_UNIFORM_MAX_LENGTH, count, 0);
|
GLES20.glGetProgramiv(programId, GLES20.GL_ACTIVE_UNIFORM_MAX_LENGTH, count, 0);
|
||||||
@ -272,7 +271,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
public void INTERNAL_applyEffect(uint pass)
|
public void INTERNAL_applyEffect(uint pass)
|
||||||
{
|
{
|
||||||
var graphicsDevice = GraphicsDevice;
|
var graphicsDevice = GraphicsDevice;
|
||||||
Renderer.Get(graphicsDevice.GLDevice).Send( () =>
|
Renderer.Get(graphicsDevice.GLDevice).Send(false, () =>
|
||||||
{
|
{
|
||||||
GLES20.glUseProgram(programId);
|
GLES20.glUseProgram(programId);
|
||||||
int n = Parameters.Count;
|
int n = Parameters.Count;
|
||||||
@ -297,7 +296,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
if (! base.IsDisposed)
|
if (! base.IsDisposed)
|
||||||
{
|
{
|
||||||
Renderer.Get(GraphicsDevice.GLDevice).Send( () =>
|
Renderer.Get(GraphicsDevice.GLDevice).Send(true, () =>
|
||||||
{
|
{
|
||||||
GLES20.glDeleteShader(fragmentId);
|
GLES20.glDeleteShader(fragmentId);
|
||||||
GLES20.glDeleteShader(vertexId);
|
GLES20.glDeleteShader(vertexId);
|
||||||
|
@ -40,7 +40,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer.Get(device).Send( () =>
|
Renderer.Get(device).Send(false, () =>
|
||||||
{
|
{
|
||||||
GLES20.glViewport(v.x, v.y, v.w, v.h);
|
GLES20.glViewport(v.x, v.y, v.w, v.h);
|
||||||
GLES20.glDepthRangef(v.minDepth, v.maxDepth);
|
GLES20.glDepthRangef(v.minDepth, v.maxDepth);
|
||||||
@ -54,7 +54,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
public static void FNA3D_SetScissorRect(IntPtr device, ref Rectangle scissor)
|
public static void FNA3D_SetScissorRect(IntPtr device, ref Rectangle scissor)
|
||||||
{
|
{
|
||||||
var s = scissor;
|
var s = scissor;
|
||||||
Renderer.Get(device).Send( () =>
|
Renderer.Get(device).Send(false, () =>
|
||||||
{
|
{
|
||||||
GLES20.glScissor(s.X, s.Y, s.Width, s.Height);
|
GLES20.glScissor(s.X, s.Y, s.Width, s.Height);
|
||||||
});
|
});
|
||||||
@ -69,7 +69,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
var clearColor = color;
|
var clearColor = color;
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
renderer.Send( () =>
|
renderer.Send(false, () =>
|
||||||
{
|
{
|
||||||
var state = (State) renderer.UserData;
|
var state = (State) renderer.UserData;
|
||||||
var WriteMask = state.WriteMask;
|
var WriteMask = state.WriteMask;
|
||||||
@ -180,8 +180,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
throw new PlatformNotSupportedException();
|
||||||
}
|
}
|
||||||
var renderer = Renderer.Get(device);
|
Renderer.Get(device).Present();
|
||||||
renderer.Present();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -192,7 +191,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
var input = blendState;
|
var input = blendState;
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
Renderer.Get(device).Send( () =>
|
Renderer.Get(device).Send(false, () =>
|
||||||
{
|
{
|
||||||
var state = (State) renderer.UserData;
|
var state = (State) renderer.UserData;
|
||||||
|
|
||||||
@ -323,7 +322,6 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
public static void FNA3D_SetDepthStencilState(IntPtr device,
|
public static void FNA3D_SetDepthStencilState(IntPtr device,
|
||||||
ref FNA3D_DepthStencilState depthStencilState)
|
ref FNA3D_DepthStencilState depthStencilState)
|
||||||
{
|
{
|
||||||
// AndroidActivity.LogI(">>>>> SET DEPTH AND STENCIL STATE");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -335,7 +333,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
var input = rasterizerState;
|
var input = rasterizerState;
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
Renderer.Get(device).Send( () =>
|
Renderer.Get(device).Send(false, () =>
|
||||||
{
|
{
|
||||||
var state = (State) renderer.UserData;
|
var state = (State) renderer.UserData;
|
||||||
|
|
||||||
@ -382,6 +380,30 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// FNA3D_GetBackbufferSize
|
||||||
|
//
|
||||||
|
|
||||||
|
public static void FNA3D_GetBackbufferSize(IntPtr device, out int w, out int h)
|
||||||
|
{
|
||||||
|
var bounds = GameRunner.Singleton.ClientBounds;
|
||||||
|
w = bounds.Width;
|
||||||
|
h = bounds.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// FNA3D_GetBackbufferSurfaceFormat
|
||||||
|
//
|
||||||
|
|
||||||
|
public static SurfaceFormat FNA3D_GetBackbufferSurfaceFormat(IntPtr device)
|
||||||
|
{
|
||||||
|
return SurfaceFormat.Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// FNA3D_GetMaxMultiSampleCount
|
||||||
|
//
|
||||||
|
|
||||||
public static int FNA3D_GetMaxMultiSampleCount(IntPtr device, SurfaceFormat format,
|
public static int FNA3D_GetMaxMultiSampleCount(IntPtr device, SurfaceFormat format,
|
||||||
int preferredMultiSampleCount)
|
int preferredMultiSampleCount)
|
||||||
{
|
{
|
||||||
@ -426,7 +448,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int indexOffset = startIndex * elementSize;
|
int indexOffset = startIndex * elementSize;
|
||||||
primitiveCount = PrimitiveCount(primitiveType, primitiveCount);
|
primitiveCount = PrimitiveCount(primitiveType, primitiveCount);
|
||||||
|
|
||||||
Renderer.Get(device).Send( () =>
|
Renderer.Get(device).Send(false, () =>
|
||||||
{
|
{
|
||||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, (int) indices);
|
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, (int) indices);
|
||||||
GLES30.glDrawRangeElements(drawMode, minVertexIndex, maxVertexIndex,
|
GLES30.glDrawRangeElements(drawMode, minVertexIndex, maxVertexIndex,
|
||||||
@ -464,7 +486,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int drawMode = PrimitiveTypeToDrawMode[(int) primitiveType];
|
int drawMode = PrimitiveTypeToDrawMode[(int) primitiveType];
|
||||||
primitiveCount = PrimitiveCount(primitiveType, primitiveCount);
|
primitiveCount = PrimitiveCount(primitiveType, primitiveCount);
|
||||||
|
|
||||||
Renderer.Get(device).Send( () =>
|
Renderer.Get(device).Send(false, () =>
|
||||||
{
|
{
|
||||||
GLES20.glDrawArrays(drawMode, vertexStart, primitiveCount);
|
GLES20.glDrawArrays(drawMode, vertexStart, primitiveCount);
|
||||||
});
|
});
|
||||||
|
@ -30,7 +30,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
private static int CreateBuffer(Renderer renderer, int target, byte dynamic, int size)
|
private static int CreateBuffer(Renderer renderer, int target, byte dynamic, int size)
|
||||||
{
|
{
|
||||||
int bufferId = 0;
|
int bufferId = 0;
|
||||||
renderer.Send( () =>
|
renderer.Send(true, () =>
|
||||||
{
|
{
|
||||||
int[] id = new int[1];
|
int[] id = new int[1];
|
||||||
GLES20.glGenBuffers(1, id, 0);
|
GLES20.glGenBuffers(1, id, 0);
|
||||||
@ -74,7 +74,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
public static void FNA3D_AddDisposeVertexBuffer(IntPtr device, IntPtr buffer)
|
public static void FNA3D_AddDisposeVertexBuffer(IntPtr device, IntPtr buffer)
|
||||||
{
|
{
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
renderer.Send( () =>
|
renderer.Send(true, () =>
|
||||||
{
|
{
|
||||||
GLES20.glDeleteBuffers(1, new int[] { (int) buffer }, 0);
|
GLES20.glDeleteBuffers(1, new int[] { (int) buffer }, 0);
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
var dataBuffer = BufferSerializer.Convert(
|
var dataBuffer = BufferSerializer.Convert(
|
||||||
dataPointer, dataLength, state, bufferId);
|
dataPointer, dataLength, state, bufferId);
|
||||||
|
|
||||||
renderer.Send( () =>
|
renderer.Send(false, () =>
|
||||||
{
|
{
|
||||||
GLES20.glBindBuffer(target, bufferId);
|
GLES20.glBindBuffer(target, bufferId);
|
||||||
|
|
||||||
@ -151,11 +151,18 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int numBindings, byte bindingsUpdated,
|
int numBindings, byte bindingsUpdated,
|
||||||
int baseVertex)
|
int baseVertex)
|
||||||
{
|
{
|
||||||
|
/* skip if FNA says the bindings have not been updated
|
||||||
|
if (baseVertex == ((State) renderer.UserData).BaseVertex.getAndSet(baseVertex))
|
||||||
|
{
|
||||||
|
if (bindingsUpdated == 0)
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
var bindingsCopy = new FNA3D_VertexBufferBinding[numBindings];
|
var bindingsCopy = new FNA3D_VertexBufferBinding[numBindings];
|
||||||
for (int i = 0; i < numBindings; i++)
|
for (int i = 0; i < numBindings; i++)
|
||||||
bindingsCopy[i] = bindings[i];
|
bindingsCopy[i] = bindings[i];
|
||||||
|
|
||||||
Renderer.Get(device).Send( () =>
|
Renderer.Get(device).Send(false, () =>
|
||||||
{
|
{
|
||||||
int nextAttribIndex = 0;
|
int nextAttribIndex = 0;
|
||||||
foreach (var binding in bindingsCopy)
|
foreach (var binding in bindingsCopy)
|
||||||
@ -278,8 +285,8 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
// we use GCHandle::FromIntPtr to convert that address to an object reference.
|
// we use GCHandle::FromIntPtr to convert that address to an object reference.
|
||||||
// see also: system.runtime.interopservices.GCHandle struct in baselib.
|
// see also: system.runtime.interopservices.GCHandle struct in baselib.
|
||||||
int offset = (int) data;
|
int offset = (int) data;
|
||||||
newBuffer = Convert(GCHandle.FromIntPtr(data - offset).Target,
|
newBuffer = Convert2(GCHandle.FromIntPtr(data - offset).Target,
|
||||||
offset, length, oldBuffer);
|
offset, length, oldBuffer);
|
||||||
|
|
||||||
if (newBuffer != oldBuffer)
|
if (newBuffer != oldBuffer)
|
||||||
{
|
{
|
||||||
@ -293,8 +300,8 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static java.nio.Buffer Convert(object data, int offset, int length,
|
private static java.nio.Buffer Convert2(object data, int offset, int length,
|
||||||
java.nio.Buffer buffer)
|
java.nio.Buffer buffer)
|
||||||
{
|
{
|
||||||
if (data is short[])
|
if (data is short[])
|
||||||
{
|
{
|
||||||
@ -491,6 +498,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
public Dictionary<int, int[]> BufferSizeUsage = new Dictionary<int, int[]>();
|
public Dictionary<int, int[]> BufferSizeUsage = new Dictionary<int, int[]>();
|
||||||
public Dictionary<int, java.nio.Buffer> BufferCache = new Dictionary<int, java.nio.Buffer>();
|
public Dictionary<int, java.nio.Buffer> BufferCache = new Dictionary<int, java.nio.Buffer>();
|
||||||
|
//public java.util.concurrent.atomic.AtomicInteger BaseVertex = new java.util.concurrent.atomic.AtomicInteger();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,20 +27,23 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
default: throw new ArgumentException("depthStencilFormat");
|
default: throw new ArgumentException("depthStencilFormat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int swapInterval = presentationParameters.presentationInterval switch
|
||||||
|
{
|
||||||
|
PresentInterval.Two => 2,
|
||||||
|
PresentInterval.Immediate => 0,
|
||||||
|
// Default, One, or any other value:
|
||||||
|
_ => 1
|
||||||
|
};
|
||||||
|
|
||||||
|
bool checkErrors = GameRunner.Singleton.CheckGlErrors();
|
||||||
|
|
||||||
var device = Renderer.Create(GameRunner.Singleton.Activity,
|
var device = Renderer.Create(GameRunner.Singleton.Activity,
|
||||||
GameRunner.Singleton.OnSurfaceChanged,
|
GameRunner.Singleton.OnSurfaceChanged,
|
||||||
8, 8, 8, 0, depthSize, stencilSize);
|
8, 8, 8, 0, depthSize, stencilSize,
|
||||||
|
swapInterval, checkErrors);
|
||||||
|
|
||||||
FNA3D_ResetBackbuffer(device, ref presentationParameters);
|
FNA3D_ResetBackbuffer(device, ref presentationParameters);
|
||||||
return device;
|
return device;
|
||||||
|
|
||||||
/*var renderer = Renderer.Get(device);
|
|
||||||
renderer.UserData = new State()
|
|
||||||
{
|
|
||||||
BackBufferWidth = presentationParameters.backBufferWidth,
|
|
||||||
BackBufferHeight = presentationParameters.backBufferHeight,
|
|
||||||
AdjustViewport = // see also FNA3D_SetViewport
|
|
||||||
(presentationParameters.displayOrientation == DisplayOrientation.Default)
|
|
||||||
};*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -27,7 +27,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
renderTargetsCopy[i] = renderTargets[i];
|
renderTargetsCopy[i] = renderTargets[i];
|
||||||
|
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
renderer.Send( () =>
|
renderer.Send(false, () =>
|
||||||
{
|
{
|
||||||
var state = (State) renderer.UserData;
|
var state = (State) renderer.UserData;
|
||||||
if (state.TargetFramebuffer == 0)
|
if (state.TargetFramebuffer == 0)
|
||||||
@ -99,7 +99,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
throw new PlatformNotSupportedException();
|
throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
renderer.Send( () =>
|
renderer.Send(false, () =>
|
||||||
{
|
{
|
||||||
GLES20.glBindFramebuffer(GLES30.GL_DRAW_FRAMEBUFFER, 0);
|
GLES20.glBindFramebuffer(GLES30.GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int texture = (int) renderTarget.texture;
|
int texture = (int) renderTarget.texture;
|
||||||
|
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
renderer.Send( () =>
|
renderer.Send(false, () =>
|
||||||
{
|
{
|
||||||
int textureUnit = GLES20.GL_TEXTURE0 + renderer.TextureUnits - 1;
|
int textureUnit = GLES20.GL_TEXTURE0 + renderer.TextureUnits - 1;
|
||||||
GLES20.glActiveTexture(textureUnit);
|
GLES20.glActiveTexture(textureUnit);
|
||||||
@ -165,7 +165,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int bufferId = 0;
|
int bufferId = 0;
|
||||||
|
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
renderer.Send( () =>
|
renderer.Send(true, () =>
|
||||||
{
|
{
|
||||||
var state = (State) renderer.UserData;
|
var state = (State) renderer.UserData;
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
public static void FNA3D_AddDisposeRenderbuffer(IntPtr device, IntPtr renderbuffer)
|
public static void FNA3D_AddDisposeRenderbuffer(IntPtr device, IntPtr renderbuffer)
|
||||||
{
|
{
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
renderer.Send( () =>
|
renderer.Send(true, () =>
|
||||||
{
|
{
|
||||||
GLES20.glDeleteRenderbuffers(1, new int[] { (int) renderbuffer }, 0);
|
GLES20.glDeleteRenderbuffers(1, new int[] { (int) renderbuffer }, 0);
|
||||||
});
|
});
|
||||||
@ -216,6 +216,8 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int x, int y, int w, int h, int level,
|
int x, int y, int w, int h, int level,
|
||||||
object dataObject, int dataOffset, int dataLength)
|
object dataObject, int dataOffset, int dataLength)
|
||||||
{
|
{
|
||||||
|
int[] tempIntArray = null;
|
||||||
|
|
||||||
java.nio.Buffer buffer = dataObject switch
|
java.nio.Buffer buffer = dataObject switch
|
||||||
{
|
{
|
||||||
sbyte[] byteArray =>
|
sbyte[] byteArray =>
|
||||||
@ -224,10 +226,18 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int[] intArray =>
|
int[] intArray =>
|
||||||
java.nio.IntBuffer.wrap(intArray, dataOffset / 4, dataLength / 4),
|
java.nio.IntBuffer.wrap(intArray, dataOffset / 4, dataLength / 4),
|
||||||
|
|
||||||
|
Color[] _ =>
|
||||||
|
// GameRunner constructor sets the marshal size of Color to -1,
|
||||||
|
// so we expect only negative or zero values here
|
||||||
|
java.nio.IntBuffer.wrap(
|
||||||
|
tempIntArray = new int[dataLength <= 0
|
||||||
|
? (dataLength = -dataLength)
|
||||||
|
: throw new ArgumentException()]),
|
||||||
|
|
||||||
_ => throw new ArgumentException(dataObject?.GetType().ToString()),
|
_ => throw new ArgumentException(dataObject?.GetType().ToString()),
|
||||||
};
|
};
|
||||||
|
|
||||||
renderer.Send( () =>
|
renderer.Send(true, () =>
|
||||||
{
|
{
|
||||||
var state = (State) renderer.UserData;
|
var state = (State) renderer.UserData;
|
||||||
if (state.SourceFramebuffer == 0)
|
if (state.SourceFramebuffer == 0)
|
||||||
@ -257,6 +267,16 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
|
|
||||||
GLES20.glBindFramebuffer(GLES30.GL_READ_FRAMEBUFFER, 0);
|
GLES20.glBindFramebuffer(GLES30.GL_READ_FRAMEBUFFER, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (tempIntArray != null)
|
||||||
|
{
|
||||||
|
if (dataOffset > 0)
|
||||||
|
throw new ArgumentException();
|
||||||
|
// convert int[] array from the GL call to a Color[] array
|
||||||
|
var colorArray = (Color[]) dataObject;
|
||||||
|
for (int i = 0; i < dataLength; i++)
|
||||||
|
colorArray[i - dataOffset].PackedValue = (uint) tempIntArray[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -90,7 +90,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
}
|
}
|
||||||
|
|
||||||
int textureId = 0;
|
int textureId = 0;
|
||||||
renderer.Send( () =>
|
renderer.Send(true, () =>
|
||||||
{
|
{
|
||||||
int id = CreateTexture(renderer, GLES20.GL_TEXTURE_2D, format, levelCount);
|
int id = CreateTexture(renderer, GLES20.GL_TEXTURE_2D, format, levelCount);
|
||||||
if (id != 0)
|
if (id != 0)
|
||||||
@ -138,7 +138,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
public static void FNA3D_AddDisposeTexture(IntPtr device, IntPtr texture)
|
public static void FNA3D_AddDisposeTexture(IntPtr device, IntPtr texture)
|
||||||
{
|
{
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
renderer.Send( () =>
|
renderer.Send(true, () =>
|
||||||
{
|
{
|
||||||
GLES20.glDeleteTextures(1, new int[] { (int) texture }, 0);
|
GLES20.glDeleteTextures(1, new int[] { (int) texture }, 0);
|
||||||
|
|
||||||
@ -165,10 +165,13 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int[] intArray =>
|
int[] intArray =>
|
||||||
java.nio.IntBuffer.wrap(intArray, dataOffset / 4, dataLength / 4),
|
java.nio.IntBuffer.wrap(intArray, dataOffset / 4, dataLength / 4),
|
||||||
|
|
||||||
|
Color[] colorArray =>
|
||||||
|
bufferFromColorArray(colorArray, dataOffset, dataLength),
|
||||||
|
|
||||||
_ => throw new ArgumentException(dataObject?.GetType().ToString()),
|
_ => throw new ArgumentException(dataObject?.GetType().ToString()),
|
||||||
};
|
};
|
||||||
|
|
||||||
renderer.Send( () =>
|
renderer.Send(false, () =>
|
||||||
{
|
{
|
||||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
|
||||||
|
|
||||||
@ -200,6 +203,20 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
java.nio.Buffer bufferFromColorArray(Color[] array, int offset, int length)
|
||||||
|
{
|
||||||
|
// GameRunner constructor sets the marshal size of Color to -1,
|
||||||
|
// so we expect only negative or zero values here
|
||||||
|
if (offset > 0 || length > 0)
|
||||||
|
throw new ArgumentException();
|
||||||
|
// convert Color[] array into an int[] array for the GL call
|
||||||
|
length = -length;
|
||||||
|
var intArray = new int[length];
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
intArray[i] = (int) array[i - offset].PackedValue;
|
||||||
|
return java.nio.IntBuffer.wrap(intArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FNA3D_SetTextureData2D(IntPtr device, IntPtr texture,
|
public static void FNA3D_SetTextureData2D(IntPtr device, IntPtr texture,
|
||||||
@ -344,7 +361,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
int textureId = (int) texture;
|
int textureId = (int) texture;
|
||||||
var renderer = Renderer.Get(device);
|
var renderer = Renderer.Get(device);
|
||||||
|
|
||||||
renderer.Send( () =>
|
renderer.Send(false, () =>
|
||||||
{
|
{
|
||||||
var state = (State) renderer.UserData;
|
var state = (State) renderer.UserData;
|
||||||
var config = state.TextureConfigs[textureId];
|
var config = state.TextureConfigs[textureId];
|
||||||
|
@ -14,8 +14,6 @@ namespace Microsoft.Xna.Framework
|
|||||||
|
|
||||||
private Activity activity;
|
private Activity activity;
|
||||||
private System.Collections.Hashtable dict;
|
private System.Collections.Hashtable dict;
|
||||||
private int clientWidth, clientHeight;
|
|
||||||
private Rectangle clientBounds;
|
|
||||||
private bool recreateActivity;
|
private bool recreateActivity;
|
||||||
|
|
||||||
private java.util.concurrent.atomic.AtomicInteger inModal;
|
private java.util.concurrent.atomic.AtomicInteger inModal;
|
||||||
@ -31,6 +29,9 @@ namespace Microsoft.Xna.Framework
|
|||||||
|
|
||||||
private const int CONFIG_EVENT = 1;
|
private const int CONFIG_EVENT = 1;
|
||||||
private const int TOUCH_EVENT = 2;
|
private const int TOUCH_EVENT = 2;
|
||||||
|
private const int KEY_EVENT = 4;
|
||||||
|
|
||||||
|
private int eventKeyCode;
|
||||||
|
|
||||||
//
|
//
|
||||||
// constructor
|
// constructor
|
||||||
@ -40,7 +41,15 @@ namespace Microsoft.Xna.Framework
|
|||||||
{
|
{
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
|
|
||||||
UpdateConfiguration(false);
|
// in Bluebonnet, the following method is used to specify the
|
||||||
|
// size that Marshal.SizeOf should return for non-primitive types.
|
||||||
|
// this is used to enable Texture2D.GetData/SetData to accept
|
||||||
|
// Color[] arrays. see also SetTextureData in FNA3D_Tex
|
||||||
|
System.Runtime.InteropServices.Marshal.SetComObjectData(
|
||||||
|
typeof(System.Runtime.InteropServices.Marshal),
|
||||||
|
typeof(Color), -1);
|
||||||
|
|
||||||
|
UpdateConfiguration();
|
||||||
|
|
||||||
inModal = new java.util.concurrent.atomic.AtomicInteger();
|
inModal = new java.util.concurrent.atomic.AtomicInteger();
|
||||||
shouldPause = new java.util.concurrent.atomic.AtomicInteger();
|
shouldPause = new java.util.concurrent.atomic.AtomicInteger();
|
||||||
@ -71,6 +80,12 @@ namespace Microsoft.Xna.Framework
|
|||||||
set => inModal.set(value ? 1 : 0);
|
set => inModal.set(value ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// CheckGlErrors
|
||||||
|
//
|
||||||
|
|
||||||
|
public bool CheckGlErrors() => activity.GetMetaAttr_Int("check.gl.errors") != 0;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Thread run() method
|
// Thread run() method
|
||||||
//
|
//
|
||||||
@ -103,6 +118,8 @@ namespace Microsoft.Xna.Framework
|
|||||||
GameRunner.Log("========================================");
|
GameRunner.Log("========================================");
|
||||||
GameRunner.Log(e.ToString());
|
GameRunner.Log(e.ToString());
|
||||||
GameRunner.Log("========================================");
|
GameRunner.Log("========================================");
|
||||||
|
if (! object.ReferenceEquals(e.InnerException, null))
|
||||||
|
e = e.InnerException;
|
||||||
System.Windows.Forms.MessageBox.Show(e.ToString());
|
System.Windows.Forms.MessageBox.Show(e.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,19 +128,13 @@ namespace Microsoft.Xna.Framework
|
|||||||
{
|
{
|
||||||
Type clsType = null;
|
Type clsType = null;
|
||||||
|
|
||||||
var clsName = activity.GetMetaAttr("main.class", true);
|
var clsName = activity.GetMetaAttr_Str("main.class", ".Program");
|
||||||
if (clsName != null)
|
if (clsName[0] == '.')
|
||||||
{
|
clsName = activity.getPackageName() + clsName;
|
||||||
if (clsName[0] == '.')
|
clsType = System.Type.GetType(clsName, false, true);
|
||||||
clsName = activity.getPackageName() + clsName;
|
|
||||||
|
|
||||||
clsType = System.Type.GetType(clsName, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clsType == null)
|
if (clsType == null)
|
||||||
{
|
|
||||||
throw new Exception($"main class '{clsName}' not found");
|
throw new Exception($"main class '{clsName}' not found");
|
||||||
}
|
|
||||||
|
|
||||||
return clsType;
|
return clsType;
|
||||||
}
|
}
|
||||||
@ -131,7 +142,7 @@ namespace Microsoft.Xna.Framework
|
|||||||
|
|
||||||
void CallMainMethod(Type mainClass)
|
void CallMainMethod(Type mainClass)
|
||||||
{
|
{
|
||||||
var method = mainClass.GetMethod("Main");
|
var method = mainClass.GetMethod("Main") ?? mainClass.GetMethod("main");
|
||||||
if (method.IsStatic)
|
if (method.IsStatic)
|
||||||
{
|
{
|
||||||
method.Invoke(null, new object[method.GetParameters().Length]);
|
method.Invoke(null, new object[method.GetParameters().Length]);
|
||||||
@ -150,6 +161,7 @@ namespace Microsoft.Xna.Framework
|
|||||||
public void MainLoop(Game game)
|
public void MainLoop(Game game)
|
||||||
{
|
{
|
||||||
int pauseCount = 0;
|
int pauseCount = 0;
|
||||||
|
bool clearKeys = false;
|
||||||
|
|
||||||
while (game.RunApplication)
|
while (game.RunApplication)
|
||||||
{
|
{
|
||||||
@ -197,12 +209,19 @@ namespace Microsoft.Xna.Framework
|
|||||||
eventBits = shouldEvents.get();
|
eventBits = shouldEvents.get();
|
||||||
|
|
||||||
if ((eventBits & CONFIG_EVENT) != 0)
|
if ((eventBits & CONFIG_EVENT) != 0)
|
||||||
UpdateConfiguration(true);
|
UpdateConfiguration();
|
||||||
|
|
||||||
if ((eventBits & TOUCH_EVENT) != 0)
|
if ((eventBits & TOUCH_EVENT) != 0)
|
||||||
{
|
{
|
||||||
Microsoft.Xna.Framework.Input.Mouse
|
Microsoft.Xna.Framework.Input.Mouse
|
||||||
.HandleEvents(clientWidth, clientHeight);
|
.HandleEvents((int) dict["width"], (int) dict["height"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((eventBits & KEY_EVENT) != 0)
|
||||||
|
{
|
||||||
|
Microsoft.Xna.Framework.Input.Keyboard.keys.Add(
|
||||||
|
(Microsoft.Xna.Framework.Input.Keys) eventKeyCode);
|
||||||
|
clearKeys = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +230,16 @@ namespace Microsoft.Xna.Framework
|
|||||||
//
|
//
|
||||||
|
|
||||||
game.Tick();
|
game.Tick();
|
||||||
|
|
||||||
|
//
|
||||||
|
// a simulated key is signalled during a single frame
|
||||||
|
//
|
||||||
|
|
||||||
|
if (clearKeys)
|
||||||
|
{
|
||||||
|
clearKeys = false;
|
||||||
|
Microsoft.Xna.Framework.Input.Keyboard.keys.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InModal = true;
|
InModal = true;
|
||||||
@ -263,12 +292,18 @@ namespace Microsoft.Xna.Framework
|
|||||||
|
|
||||||
public void ActivityPause()
|
public void ActivityPause()
|
||||||
{
|
{
|
||||||
if (! InModal)
|
if (shouldResume.get() == 0)
|
||||||
{
|
{
|
||||||
shouldPause.incrementAndGet();
|
Microsoft.Xna.Framework.Media.MediaPlayer.ActivityPauseOrResume(true);
|
||||||
waitForPause.block();
|
Microsoft.Xna.Framework.Audio.SoundEffect.ActivityPauseOrResume(true);
|
||||||
if (shouldExit.get() == 0)
|
|
||||||
waitForPause.close();
|
if (! InModal)
|
||||||
|
{
|
||||||
|
shouldPause.incrementAndGet();
|
||||||
|
waitForPause.block();
|
||||||
|
if (shouldExit.get() == 0)
|
||||||
|
waitForPause.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +314,16 @@ namespace Microsoft.Xna.Framework
|
|||||||
public void ActivityResume()
|
public void ActivityResume()
|
||||||
{
|
{
|
||||||
if (shouldResume.compareAndSet(1, 0))
|
if (shouldResume.compareAndSet(1, 0))
|
||||||
|
{
|
||||||
|
// force a call to UpdateConfiguration after main loop wakes up.
|
||||||
|
// this will not actually invoke callbacks if nothing has changed.
|
||||||
|
OnSurfaceChanged();
|
||||||
|
|
||||||
waitForResume.open();
|
waitForResume.open();
|
||||||
|
|
||||||
|
Microsoft.Xna.Framework.Media.MediaPlayer.ActivityPauseOrResume(false);
|
||||||
|
Microsoft.Xna.Framework.Audio.SoundEffect.ActivityPauseOrResume(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -308,6 +352,23 @@ namespace Microsoft.Xna.Framework
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ActivityKey
|
||||||
|
//
|
||||||
|
|
||||||
|
public void ActivityKey(int keyCode)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int v = shouldEvents.get();
|
||||||
|
if (shouldEvents.compareAndSet(v, v | KEY_EVENT))
|
||||||
|
{
|
||||||
|
eventKeyCode = keyCode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// OnSurfaceChanged
|
// OnSurfaceChanged
|
||||||
//
|
//
|
||||||
@ -326,26 +387,76 @@ namespace Microsoft.Xna.Framework
|
|||||||
// UpdateConfiguration
|
// UpdateConfiguration
|
||||||
//
|
//
|
||||||
|
|
||||||
void UpdateConfiguration(bool withCallback)
|
void UpdateConfiguration()
|
||||||
{
|
{
|
||||||
var metrics = new android.util.DisplayMetrics();
|
var metrics = GetDisplayMetrics(activity);
|
||||||
activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
|
int width = metrics.widthPixels;
|
||||||
|
int height = metrics.heightPixels;
|
||||||
|
|
||||||
clientWidth = metrics.widthPixels;
|
var dict = new System.Collections.Hashtable();
|
||||||
clientHeight = metrics.heightPixels;
|
|
||||||
clientBounds = new Rectangle(0, 0, clientWidth, clientHeight);
|
|
||||||
|
|
||||||
if (dict == null)
|
dict["width"] = width;
|
||||||
dict = new System.Collections.Hashtable();
|
dict["height"] = height;
|
||||||
|
dict["dpi"] = (int) ((metrics.xdpi + metrics.ydpi) * 0.5f);
|
||||||
|
|
||||||
// int dpi - pixels per inch
|
if (object.ReferenceEquals(this.dict, null))
|
||||||
dict["dpi"] = (int) ((metrics.xdpi + metrics.ydpi) * 0.5f);
|
|
||||||
|
|
||||||
if (withCallback)
|
|
||||||
{
|
{
|
||||||
|
// on first call, set the dict without invoking callbacks
|
||||||
|
SetExtra(dict, width, height);
|
||||||
|
this.dict = dict;
|
||||||
|
}
|
||||||
|
else if (! DictsEqual(dict, this.dict))
|
||||||
|
{
|
||||||
|
SetExtra(dict, width, height);
|
||||||
|
this.dict = dict;
|
||||||
|
|
||||||
OnClientSizeChanged();
|
OnClientSizeChanged();
|
||||||
OnOrientationChanged();
|
OnOrientationChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
android.util.DisplayMetrics GetDisplayMetrics(android.app.Activity activity)
|
||||||
|
{
|
||||||
|
bool isMultiWindow = false;
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= 24)
|
||||||
|
isMultiWindow = activity.isInMultiWindowMode();
|
||||||
|
|
||||||
|
var metrics = new android.util.DisplayMetrics();
|
||||||
|
var display = activity.getWindowManager().getDefaultDisplay();
|
||||||
|
if (! isMultiWindow)
|
||||||
|
{
|
||||||
|
// getRealMetrics gets real size of the entire screen.
|
||||||
|
// this is what we need in full screen immersive mode.
|
||||||
|
display.getRealMetrics(metrics);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// getMetrics gets the size of the split window, minus
|
||||||
|
// window frames. this is useful in multi-window mode.
|
||||||
|
display.getMetrics(metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
return metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DictsEqual(System.Collections.Hashtable dict1,
|
||||||
|
System.Collections.Hashtable dict2)
|
||||||
|
{
|
||||||
|
foreach (var key in dict1.Keys)
|
||||||
|
{
|
||||||
|
if (! dict1[key].Equals(dict2[key]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetExtra(System.Collections.Hashtable dict, int width, int height)
|
||||||
|
{
|
||||||
|
dict["bounds"] = new Rectangle(0, 0, width, height);
|
||||||
|
dict["openUri"] = (Action<string>) OpenUri;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -359,11 +470,32 @@ namespace Microsoft.Xna.Framework
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// OpenUri
|
||||||
|
//
|
||||||
|
|
||||||
|
private void OpenUri(string uri)
|
||||||
|
{
|
||||||
|
activity.runOnUiThread(((java.lang.Runnable.Delegate) (() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
activity.startActivity(
|
||||||
|
new android.content.Intent(android.content.Intent.ACTION_VIEW,
|
||||||
|
android.net.Uri.parse(uri)));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
GameRunner.Log(e.ToString());
|
||||||
|
}
|
||||||
|
})).AsInterface());
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// GameWindow interface
|
// GameWindow interface
|
||||||
//
|
//
|
||||||
|
|
||||||
public override Rectangle ClientBounds => clientBounds;
|
public override Rectangle ClientBounds => (Rectangle) dict["bounds"];
|
||||||
|
|
||||||
public override string ScreenDeviceName => "Android";
|
public override string ScreenDeviceName => "Android";
|
||||||
|
|
||||||
@ -374,8 +506,8 @@ namespace Microsoft.Xna.Framework
|
|||||||
|
|
||||||
public override DisplayOrientation CurrentOrientation
|
public override DisplayOrientation CurrentOrientation
|
||||||
{
|
{
|
||||||
get => (clientWidth < clientHeight) ? DisplayOrientation.Portrait
|
get => ((int) dict["width"] < (int) dict["height"])
|
||||||
: DisplayOrientation.LandscapeLeft;
|
? DisplayOrientation.Portrait : DisplayOrientation.LandscapeLeft;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
bool portrait = 0 != (value & DisplayOrientation.Portrait);
|
bool portrait = 0 != (value & DisplayOrientation.Portrait);
|
||||||
@ -387,7 +519,7 @@ namespace Microsoft.Xna.Framework
|
|||||||
else if (landscape && (! portrait))
|
else if (landscape && (! portrait))
|
||||||
r = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;
|
r = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;
|
||||||
else
|
else
|
||||||
r = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
|
return;
|
||||||
activity.setRequestedOrientation(r);
|
activity.setRequestedOrientation(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,6 +201,12 @@ namespace Microsoft.Xna.Framework.Input
|
|||||||
public int Y { get; set; }
|
public int Y { get; set; }
|
||||||
public ButtonState LeftButton { get; set; }
|
public ButtonState LeftButton { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[java.attr.Discard] // discard in output
|
||||||
|
public static class Keyboard
|
||||||
|
{
|
||||||
|
public static List<Keys> keys;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ namespace Microsoft.Xna.Framework.Media
|
|||||||
[java.attr.RetainType] private static float volume;
|
[java.attr.RetainType] private static float volume;
|
||||||
[java.attr.RetainType] private static bool muted;
|
[java.attr.RetainType] private static bool muted;
|
||||||
[java.attr.RetainType] private static bool looping;
|
[java.attr.RetainType] private static bool looping;
|
||||||
|
[java.attr.RetainType] private static bool wasPlayingBeforeActivityPause;
|
||||||
|
|
||||||
//
|
//
|
||||||
// static constructor
|
// static constructor
|
||||||
@ -283,6 +284,28 @@ namespace Microsoft.Xna.Framework.Media
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ActivityPauseOrResume
|
||||||
|
//
|
||||||
|
|
||||||
|
public static void ActivityPauseOrResume(bool pausing)
|
||||||
|
{
|
||||||
|
if (pausing)
|
||||||
|
{
|
||||||
|
if (State == MediaState.Playing)
|
||||||
|
{
|
||||||
|
wasPlayingBeforeActivityPause = true;
|
||||||
|
Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (wasPlayingBeforeActivityPause)
|
||||||
|
{
|
||||||
|
wasPlayingBeforeActivityPause = false;
|
||||||
|
Resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -20,6 +20,8 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
private android.os.ConditionVariable waitObject;
|
private android.os.ConditionVariable waitObject;
|
||||||
private java.util.concurrent.atomic.AtomicInteger paused;
|
private java.util.concurrent.atomic.AtomicInteger paused;
|
||||||
private Action actionOnChanged;
|
private Action actionOnChanged;
|
||||||
|
private int swapInterval;
|
||||||
|
private bool checkErrors;
|
||||||
|
|
||||||
public object UserData;
|
public object UserData;
|
||||||
|
|
||||||
@ -39,11 +41,14 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
|
|
||||||
private Renderer(android.app.Activity activity, Action onChanged,
|
private Renderer(android.app.Activity activity, Action onChanged,
|
||||||
int redSize, int greenSize, int blueSize,
|
int redSize, int greenSize, int blueSize,
|
||||||
int alphaSize, int depthSize, int stencilSize)
|
int alphaSize, int depthSize, int stencilSize,
|
||||||
|
int swapInterval, bool checkErrors)
|
||||||
{
|
{
|
||||||
waitObject = new android.os.ConditionVariable();
|
waitObject = new android.os.ConditionVariable();
|
||||||
paused = new java.util.concurrent.atomic.AtomicInteger();
|
paused = new java.util.concurrent.atomic.AtomicInteger();
|
||||||
actionOnChanged = onChanged;
|
actionOnChanged = onChanged;
|
||||||
|
this.swapInterval = swapInterval;
|
||||||
|
this.checkErrors = checkErrors;
|
||||||
|
|
||||||
activity.runOnUiThread(((java.lang.Runnable.Delegate) (() =>
|
activity.runOnUiThread(((java.lang.Runnable.Delegate) (() =>
|
||||||
{
|
{
|
||||||
@ -55,7 +60,6 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
surface.setRenderer(this);
|
surface.setRenderer(this);
|
||||||
surface.setRenderMode(android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
surface.setRenderMode(android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
||||||
activity.setContentView(surface);
|
activity.setContentView(surface);
|
||||||
|
|
||||||
})).AsInterface());
|
})).AsInterface());
|
||||||
|
|
||||||
// wait for one onDrawFrame callback, which tells us that
|
// wait for one onDrawFrame callback, which tells us that
|
||||||
@ -78,16 +82,21 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
// Send
|
// Send
|
||||||
//
|
//
|
||||||
|
|
||||||
public void Send(Action action)
|
public void Send(bool wait, Action action)
|
||||||
{
|
{
|
||||||
Exception exc = null;
|
Exception exc = null;
|
||||||
if (paused.get() == 0)
|
if (paused.get() == 0)
|
||||||
{
|
{
|
||||||
var cond = new android.os.ConditionVariable();
|
if (! waitObject.block(2000))
|
||||||
surface.queueEvent(((java.lang.Runnable.Delegate) (() =>
|
|
||||||
{
|
{
|
||||||
var error = GLES20.glGetError();
|
// see also Present(). a timeout here means that onDrawFrame
|
||||||
if (error == GLES20.GL_NO_ERROR)
|
// was never called, so the surface was probably destroyed.
|
||||||
|
paused.compareAndSet(0, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var cond = wait ? new android.os.ConditionVariable() : null;
|
||||||
|
surface.queueEvent(((java.lang.Runnable.Delegate) (() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -97,18 +106,21 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
exc = exc2;
|
exc = exc2;
|
||||||
}
|
}
|
||||||
error = GLES20.glGetError();
|
if (checkErrors)
|
||||||
}
|
{
|
||||||
if (error != GLES20.GL_NO_ERROR)
|
var error = GLES20.glGetError();
|
||||||
exc = new Exception($"GL Error {error}");
|
if (error != GLES20.GL_NO_ERROR)
|
||||||
cond.open();
|
exc = new Exception($"GL Error {error}");
|
||||||
})).AsInterface());
|
}
|
||||||
cond.block();
|
if (cond != null)
|
||||||
|
cond.open();
|
||||||
|
})).AsInterface());
|
||||||
|
if (cond != null)
|
||||||
|
cond.block();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (exc != null)
|
if (exc != null)
|
||||||
{
|
|
||||||
throw new AggregateException(exc.Message, exc);
|
throw new AggregateException(exc.Message, exc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -119,7 +131,19 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
waitObject.close();
|
waitObject.close();
|
||||||
surface.requestRender();
|
surface.requestRender();
|
||||||
waitObject.block();
|
|
||||||
|
// GLSurfaceView runs queued events before checking if render
|
||||||
|
// was requested; but if the event queue is empty, it checks
|
||||||
|
// if render requested, then calls onDrawFrame(). thus the
|
||||||
|
// sequence of events is as follows:
|
||||||
|
|
||||||
|
// - Present() blocks waitObject and requests render
|
||||||
|
// - any events already queued by Send() are processed by
|
||||||
|
// GLSurfaceView, before it checks for a requested render.
|
||||||
|
// - Send() delays any new events until waitObject is opened.
|
||||||
|
// - OnDrawFrame() is called and opens waitObject, and when
|
||||||
|
// it returns to GLSurfaceView, the GL buffers are swapped.
|
||||||
|
// - with waitObject open, Send() queues new events.
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -132,6 +156,17 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
// if onSurfaceCreated is called while resuming from pause,
|
// if onSurfaceCreated is called while resuming from pause,
|
||||||
// it means the GL context was lost
|
// it means the GL context was lost
|
||||||
paused.compareAndSet(1, -1);
|
paused.compareAndSet(1, -1);
|
||||||
|
|
||||||
|
// assign high priority to the rendering thread
|
||||||
|
java.lang.Thread.currentThread()
|
||||||
|
.setPriority(java.lang.Thread.MAX_PRIORITY);
|
||||||
|
|
||||||
|
// set swap interval
|
||||||
|
if (swapInterval != 1)
|
||||||
|
{
|
||||||
|
var eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
|
||||||
|
EGL14.eglSwapInterval(eglDisplay, swapInterval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[java.attr.RetainName]
|
[java.attr.RetainName]
|
||||||
@ -188,7 +223,8 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
|
|
||||||
public static IntPtr Create(android.app.Activity activity, Action onChanged,
|
public static IntPtr Create(android.app.Activity activity, Action onChanged,
|
||||||
int redSize, int greenSize, int blueSize,
|
int redSize, int greenSize, int blueSize,
|
||||||
int alphaSize, int depthSize, int stencilSize)
|
int alphaSize, int depthSize, int stencilSize,
|
||||||
|
int swapInterval, bool checkErrors)
|
||||||
{
|
{
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -216,7 +252,8 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
deviceId = deviceId,
|
deviceId = deviceId,
|
||||||
renderer = new Renderer(activity, onChanged,
|
renderer = new Renderer(activity, onChanged,
|
||||||
redSize, greenSize, blueSize,
|
redSize, greenSize, blueSize,
|
||||||
alphaSize, depthSize, stencilSize),
|
alphaSize, depthSize, stencilSize,
|
||||||
|
swapInterval, checkErrors),
|
||||||
activity = new java.lang.@ref.WeakReference(activity),
|
activity = new java.lang.@ref.WeakReference(activity),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -290,7 +327,7 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
foreach (var renderer in GetRenderersForActivity(activity))
|
foreach (var renderer in GetRenderersForActivity(activity))
|
||||||
{
|
{
|
||||||
renderer.surface.onPause();
|
renderer.surface.onPause();
|
||||||
renderer.paused.set(1);
|
renderer.paused.compareAndSet(0, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,9 +341,20 @@ namespace Microsoft.Xna.Framework.Graphics
|
|||||||
{
|
{
|
||||||
if (renderer.paused.get() != 0)
|
if (renderer.paused.get() != 0)
|
||||||
{
|
{
|
||||||
renderer.waitObject.close();
|
// we cannot use waitObject for resuming, because the surface
|
||||||
|
// may have been destroyed between pause and resume, in which
|
||||||
|
// case onDrawFrame would not get called.
|
||||||
|
|
||||||
|
var cond = new android.os.ConditionVariable();
|
||||||
|
renderer.surface.queueEvent(((java.lang.Runnable.Delegate) (
|
||||||
|
() => cond.open() )).AsInterface());
|
||||||
|
|
||||||
renderer.surface.onResume();
|
renderer.surface.onResume();
|
||||||
renderer.waitObject.block();
|
if (! cond.block(2000))
|
||||||
|
{
|
||||||
|
// something is wrong if the queued event did not run
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (! renderer.paused.compareAndSet(1, 0))
|
if (! renderer.paused.compareAndSet(1, 0))
|
||||||
{
|
{
|
||||||
|
@ -264,6 +264,29 @@ namespace Microsoft.Xna.Framework.Audio
|
|||||||
public static float DistanceScale { get; set; }
|
public static float DistanceScale { get; set; }
|
||||||
public static float DopplerScale { get; set; }
|
public static float DopplerScale { get; set; }
|
||||||
public static float SpeedOfSound { get; set; }
|
public static float SpeedOfSound { get; set; }
|
||||||
|
|
||||||
|
//
|
||||||
|
// ActivityPauseOrResume
|
||||||
|
//
|
||||||
|
|
||||||
|
public static void ActivityPauseOrResume(bool pausing)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
instancesLock.@lock();
|
||||||
|
int num = instancesList.size();
|
||||||
|
for (int idx = 0; idx < num; idx++)
|
||||||
|
{
|
||||||
|
var instRef = (java.lang.@ref.WeakReference) instancesList.get(idx);
|
||||||
|
((SoundEffectInstance) instRef.get())?.ActivityPauseOrResume(pausing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
instancesLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -279,6 +302,7 @@ namespace Microsoft.Xna.Framework.Audio
|
|||||||
[java.attr.RetainType] private android.media.AudioTrack track;
|
[java.attr.RetainType] private android.media.AudioTrack track;
|
||||||
[java.attr.RetainType] private float pitch, pan, volume;
|
[java.attr.RetainType] private float pitch, pan, volume;
|
||||||
[java.attr.RetainType] private bool isLooped;
|
[java.attr.RetainType] private bool isLooped;
|
||||||
|
[java.attr.RetainType] private bool wasPlayingBeforeActivityPause;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Constructor (for SoundEffect.CreateInstance)
|
// Constructor (for SoundEffect.CreateInstance)
|
||||||
@ -595,6 +619,27 @@ namespace Microsoft.Xna.Framework.Audio
|
|||||||
public void Apply3D(AudioListener listener, AudioEmitter emitter) { }
|
public void Apply3D(AudioListener listener, AudioEmitter emitter) { }
|
||||||
public void Apply3D(AudioListener[] listeners, AudioEmitter emitter) { }
|
public void Apply3D(AudioListener[] listeners, AudioEmitter emitter) { }
|
||||||
|
|
||||||
|
//
|
||||||
|
// ActivityPauseOrResume
|
||||||
|
//
|
||||||
|
|
||||||
|
public void ActivityPauseOrResume(bool pausing)
|
||||||
|
{
|
||||||
|
if (pausing)
|
||||||
|
{
|
||||||
|
if (State == SoundState.Playing)
|
||||||
|
{
|
||||||
|
wasPlayingBeforeActivityPause = true;
|
||||||
|
Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (wasPlayingBeforeActivityPause)
|
||||||
|
{
|
||||||
|
wasPlayingBeforeActivityPause = false;
|
||||||
|
Resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
package="com.spaceflint.bluebonnet.xnademo1">
|
package="com.spaceflint.bluebonnet.xnademo1">
|
||||||
|
|
||||||
<!-- API 18, GLES 3.0 -->
|
<!-- API 18, GLES 3.0 -->
|
||||||
|
<!-- note that if testing in the Android emulator, you may need to add
|
||||||
|
the following line in your ~/.android/advancedFeatures.ini file:
|
||||||
|
GLESDynamicVersion=on
|
||||||
|
!-->
|
||||||
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="29" />
|
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="29" />
|
||||||
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
|
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
|
||||||
|
|
||||||
@ -15,7 +19,10 @@
|
|||||||
|
|
||||||
<application android:label="BNA_Demo1"
|
<application android:label="BNA_Demo1"
|
||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
android:isGame="true" >
|
android:isGame="true"
|
||||||
|
android:resizeableActivity="true"
|
||||||
|
android:supportsPictureInPicture="true"
|
||||||
|
>
|
||||||
|
|
||||||
<!-- set android:screenOrientation if you need to lock orientation:
|
<!-- set android:screenOrientation if you need to lock orientation:
|
||||||
https://developer.android.com/guide/topics/manifest/activity-element#screen -->
|
https://developer.android.com/guide/topics/manifest/activity-element#screen -->
|
||||||
@ -29,21 +36,38 @@
|
|||||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
|
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
|
||||||
android:immersive="true"
|
android:immersive="true"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
|
android:maxAspectRatio="9"
|
||||||
>
|
>
|
||||||
|
|
||||||
<!-- microsoft.xna.framework.log.tag sets the log identifier
|
<!-- the name of the main entrypoint class. if starts with a dot,
|
||||||
for log messages printed via android.util.Log by the app.
|
then it is appended to the namespace specifies in the package
|
||||||
if omitted, the default is 'BNA_Game' -->
|
attribute. the default is '.Program' -->
|
||||||
|
<meta-data android:name="BNA.main.class" android:value=".Program"/>
|
||||||
|
|
||||||
<meta-data android:name="microsoft.xna.framework.log.tag"
|
<!-- the log identifier for log messages printed via android.util.Log
|
||||||
android:value="BNA_Demo1"/>
|
by the app. the default is 'BNA_Game' -->
|
||||||
|
<meta-data android:name="BNA.log.tag" android:value="BNA_Demo1"/>
|
||||||
|
|
||||||
<!-- microsoft.xna.framework.main.class sets the name of the main
|
<!-- specifies whether to call glGetError() after every GL call.
|
||||||
or entrypoint class. if starts with a dot, it is appended
|
non-zero value enables error checks, zero skips error checks.
|
||||||
to the namespace specifies in the package attribute. -->
|
this has a negative impact on performance, and is not recommended
|
||||||
|
in production builds. the default is '0' -->
|
||||||
|
<meta-data android:name="BNA.check.gl.errors" android:value="0"/>
|
||||||
|
|
||||||
<meta-data android:name="microsoft.xna.framework.main.class"
|
<!-- specifies whether to disable screen timeout, if set to a non-zero
|
||||||
android:value=".Program"/>
|
value. the default is '0' -->
|
||||||
|
<meta-data android:name="BNA.keep.screen.on" android:value="0"/>
|
||||||
|
|
||||||
|
<!-- specifies whether to enable full screen immersive mode, if set
|
||||||
|
to a non-zero value. the default is '0' -->
|
||||||
|
<meta-data android:name="BNA.immersive.mode" android:value="0"/>
|
||||||
|
|
||||||
|
<!-- specifies the key to signal, for one frame, when the back button
|
||||||
|
is pressed. if omitted or specified as zero, default handling of
|
||||||
|
the back button occurs, which typically stops the activity.
|
||||||
|
Escape = Microsoft.Xna.Framework.Input.Keys.Escape = 27.
|
||||||
|
Back = Microsoft.Xna.Framework.Input.Keys.Back = 8. -->
|
||||||
|
<meta-data android:name="BNA.back.key" android:value="0"/>
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@ -51,6 +75,15 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<meta-data android:name="android.max_aspect" android:value="9" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
<supports-screens android:smallScreens="true"
|
||||||
|
android:normalScreens="true"
|
||||||
|
android:largeScreens="true"
|
||||||
|
android:xlargeScreens="true"
|
||||||
|
android:anyDensity="true" />
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
APK_TEMP_DIR = directory where APK processing occurs
|
APK_TEMP_DIR = directory where APK processing occurs
|
||||||
e.g. $(OutputDir)/MyGame/Debug/Content
|
e.g. $(OutputDir)/MyGame/Debug/Content
|
||||||
|
IMPORTANT: this directory will be deleted and recreated!
|
||||||
|
|
||||||
KEYSTORE_FILE = path to a keystore file used in APK signing
|
KEYSTORE_FILE = path to a keystore file used in APK signing
|
||||||
|
|
||||||
@ -33,8 +34,6 @@
|
|||||||
|
|
||||||
BLUEBONNET_EXE = path to Bluebonnet.exe program file
|
BLUEBONNET_EXE = path to Bluebonnet.exe program file
|
||||||
|
|
||||||
BLUEBONNET_JAR = path to Baselib.jar file from Bluebonnet
|
|
||||||
|
|
||||||
ANDROID_JAR = path to Android.jar file, for desired API level
|
ANDROID_JAR = path to Android.jar file, for desired API level
|
||||||
e.g. $(ANDROID_HOME)/android-28/android.jar
|
e.g. $(ANDROID_HOME)/android-28/android.jar
|
||||||
|
|
||||||
|
24
build_bna.bat
Normal file
24
build_bna.bat
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
@echo off
|
||||||
|
if "%ANDROID_JAR%" == "" (
|
||||||
|
echo Missing environment variable ANDROID_JAR.
|
||||||
|
echo It should specify the full path to an Android.jar file in the platforms directory of the Android SDK.
|
||||||
|
goto :EOF
|
||||||
|
)
|
||||||
|
if "%FNA_DLL%" == "" (
|
||||||
|
echo Missing environment variable FNA_DLL.
|
||||||
|
echo It should specify the full path to the FNA.DLL file.
|
||||||
|
goto :EOF
|
||||||
|
)
|
||||||
|
if "%BLUEBONNET_EXE%" == "" (
|
||||||
|
echo Missing environment variable BLUEBONNET_EXE.
|
||||||
|
echo It should specify the full path to the Bluebonnet executable.
|
||||||
|
goto :EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
echo Building BNA. Command:
|
||||||
|
echo MSBuild BNA -p:Configuration=Release
|
||||||
|
echo ========================================
|
||||||
|
MSBuild BNA -p:Configuration=Release
|
||||||
|
|
||||||
|
:EOF
|
Loading…
x
Reference in New Issue
Block a user