зеркало из https://github.com/xamarin/ios-samples.git
369 строки
12 KiB
C#
369 строки
12 KiB
C#
using System;
|
|
using CoreGraphics;
|
|
|
|
using OpenTK.Graphics.ES20;
|
|
using OpenTK;
|
|
|
|
using OpenGLES;
|
|
using CoreAnimation;
|
|
using Foundation;
|
|
using GLKit;
|
|
using UIKit;
|
|
|
|
namespace OpenGLScroller
|
|
{
|
|
public class CubeView : GLKView
|
|
{
|
|
const int NumLittleCubes = 20;
|
|
const float LittleCubeWidth = (320 / 3);
|
|
const float ScrollerHeight = LittleCubeWidth;
|
|
const float UnitLittleCubeWidth = 2;
|
|
|
|
int vertexArray;
|
|
int vertexBuffer;
|
|
|
|
float[] gCubeVertexData =
|
|
{
|
|
// Data layout for each line below is:
|
|
// positionX, positionY, positionZ, normalX, normalY, normalZ,
|
|
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
|
|
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
|
|
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
|
|
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
|
|
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
|
|
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
|
|
|
|
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
|
|
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
|
|
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
|
|
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
|
|
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
|
|
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
|
|
|
|
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
|
|
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
|
|
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
|
|
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
|
|
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
|
|
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
|
|
|
|
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
|
|
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
|
|
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
|
|
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
|
|
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
|
|
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
|
|
|
|
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
|
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
|
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
|
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
|
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
|
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
|
|
|
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
|
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
|
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
|
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
|
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
|
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f
|
|
};
|
|
|
|
struct CubeInfo
|
|
{
|
|
public float Red;
|
|
public float Green;
|
|
public float Blue;
|
|
public float XAxis;
|
|
public float YAxis;
|
|
public float ZAxis;
|
|
public float Speed;
|
|
public float RotationRadians;
|
|
|
|
public CubeInfo (float r, float g, float b, float x, float y, float z, float s, float rr)
|
|
{
|
|
Red = r;
|
|
Green = g;
|
|
Blue = b;
|
|
XAxis = x;
|
|
YAxis = y;
|
|
ZAxis = z;
|
|
Speed = s;
|
|
RotationRadians = rr;
|
|
}
|
|
};
|
|
|
|
CubeInfo [] littleCube = new CubeInfo [NumLittleCubes];
|
|
CubeInfo bigCube = new CubeInfo ();
|
|
CubeInfo bigCubeDirections = new CubeInfo ();
|
|
|
|
CubeInfo minimums = new CubeInfo (0.1f, 0.1f, 0.1f, -1.0f, -1.0f, -1.0f, -0.5f, 0.0f);
|
|
CubeInfo maximums = new CubeInfo (1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.5f, (float) Math.PI * 2);
|
|
CubeInfo deltas = new CubeInfo (0.02f, 0.018f, 0.016f, 0.01f, 0.02f, 0.03f, 0.01f, 0.0f);
|
|
|
|
double timeOfLastRenderedFrame;
|
|
public CGPoint scrollOffset;
|
|
|
|
GLKBaseEffect effect;
|
|
Random gen = new Random();
|
|
|
|
public CubeView (CGRect frame) : base (frame)
|
|
{
|
|
SetupGL ();
|
|
}
|
|
|
|
public CGRect ScrollableFrame {
|
|
get {
|
|
return new CGRect (0, 30, 320, (int)ScrollerHeight);
|
|
}
|
|
}
|
|
|
|
public CGSize ScrollableContentSize {
|
|
get {
|
|
float width = NumLittleCubes * LittleCubeWidth;
|
|
return new CGSize ((int)width, (int)ScrollerHeight);
|
|
}
|
|
}
|
|
|
|
public CGPoint GetScrollOffset (CGPoint offset)
|
|
{
|
|
nfloat fractionalPart = offset.X % LittleCubeWidth;
|
|
|
|
bool roundDown = fractionalPart < (LittleCubeWidth / 2);
|
|
|
|
if (roundDown) {
|
|
offset.X -= (int) fractionalPart;
|
|
} else {
|
|
offset.X += (int) (LittleCubeWidth - fractionalPart);
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
public override CGRect Frame {
|
|
get {
|
|
return base.Frame;
|
|
}
|
|
set {
|
|
base.Frame = value;
|
|
|
|
float aspect = (float)Math.Abs (Bounds.Size.Width / Bounds.Size.Height);
|
|
|
|
Matrix4 projectionMatrix = Matrix4.CreatePerspectiveFieldOfView (MathHelper.DegreesToRadians (65), aspect, 0.1f, 100);
|
|
if (effect != null)
|
|
effect.Transform.ProjectionMatrix = projectionMatrix;
|
|
}
|
|
}
|
|
|
|
public override void Draw (CGRect rect)
|
|
{
|
|
UpdateCubes ();
|
|
|
|
GL.ClearColor (0.15f, 0.15f, 0.15f, 1);
|
|
GL.Clear (ClearBufferMask.ColorBufferBit);
|
|
GL.Clear (ClearBufferMask.DepthBufferBit);
|
|
|
|
GL.Oes.BindVertexArray (vertexArray);
|
|
|
|
for (int i = 0; i < NumLittleCubes; i++) {
|
|
var cube = littleCube [i];
|
|
|
|
var translationX = ((i - 1) * UnitLittleCubeWidth) - (scrollOffset.X * UnitLittleCubeWidth / LittleCubeWidth);
|
|
var cubeMatrix = Matrix4.CreateTranslation ((float)translationX, 2.8f, -7);
|
|
cubeMatrix = Matrix4.Mult (Matrix4.CreateFromAxisAngle (new Vector3 (cube.XAxis, cube.YAxis, cube.ZAxis), cube.RotationRadians), cubeMatrix);
|
|
|
|
effect.Light0.DiffuseColor = new Vector4 (cube.Red, cube.Green, cube.Blue, 1.0f);
|
|
effect.Transform.ModelViewMatrix = cubeMatrix;
|
|
|
|
effect.PrepareToDraw();
|
|
|
|
GL.DrawArrays (BeginMode.Triangles, 0, 36);
|
|
}
|
|
|
|
var bigCubeMatrix = Matrix4.CreateTranslation (0, -0.5f, -3);
|
|
|
|
bigCubeMatrix = Matrix4.Mult (Matrix4.CreateFromAxisAngle (new Vector3 (bigCube.XAxis, bigCube.YAxis, bigCube.ZAxis), bigCube.RotationRadians), bigCubeMatrix);
|
|
|
|
effect.Light0.DiffuseColor = new Vector4 (bigCube.Red, bigCube.Green, bigCube.Blue, 0.5f);
|
|
effect.Transform.ModelViewMatrix = bigCubeMatrix;
|
|
|
|
effect.PrepareToDraw ();
|
|
|
|
GL.DrawArrays (BeginMode.Triangles, 0, 36);
|
|
}
|
|
|
|
public override void TouchesBegan (NSSet touches, UIEvent evt)
|
|
{
|
|
base.TouchesBegan (touches, evt);
|
|
}
|
|
|
|
public override void TouchesMoved (NSSet touches, UIEvent evt)
|
|
{
|
|
base.TouchesMoved (touches, evt);
|
|
}
|
|
|
|
public override void TouchesCancelled (NSSet touches, UIEvent evt)
|
|
{
|
|
base.TouchesCancelled (touches, evt);
|
|
}
|
|
|
|
public override void TouchesEnded (NSSet touches, UIEvent evt)
|
|
{
|
|
var touch = (UITouch) touches.AnyObject;
|
|
if (touch.TapCount == 1) {
|
|
var endTouch = new CGPoint (touch.LocationInView (this).X, touch.LocationInView (this).Y);
|
|
HandleTapAtPoint (endTouch);
|
|
}
|
|
}
|
|
|
|
public void HandleTapAtPoint (CGPoint point)
|
|
{
|
|
var bigCubeRect = new CGRect (70, 210, 180, 180);
|
|
CGRect scrollviewRect = ScrollableFrame;
|
|
|
|
if (bigCubeRect.Contains (point.X, point.Y)) {
|
|
HandleBigCubeTap ();
|
|
} else if (scrollviewRect.Contains (point.X, point.Y)) {
|
|
var adjustedX = point.X + scrollOffset.X;
|
|
|
|
int cubeIndex = (int) Math.Floor (adjustedX / LittleCubeWidth);
|
|
HandleLittleCubeTap (cubeIndex);
|
|
}
|
|
}
|
|
|
|
public void HandleBigCubeTap ()
|
|
{
|
|
RandomizeBigCube ();
|
|
}
|
|
|
|
public void HandleLittleCubeTap (int index)
|
|
{
|
|
littleCube [index] = bigCube;
|
|
}
|
|
|
|
public void SetupGL ()
|
|
{
|
|
Context = new EAGLContext (EAGLRenderingAPI.OpenGLES2);
|
|
DrawableDepthFormat = GLKViewDrawableDepthFormat.Format24;
|
|
|
|
effect = new GLKBaseEffect ();
|
|
effect.Light0.Enabled = true;
|
|
|
|
EAGLContext.SetCurrentContext (Context);
|
|
|
|
GL.Enable (EnableCap.DepthTest);
|
|
|
|
GL.Oes.GenVertexArrays (1, out vertexArray);
|
|
GL.Oes.BindVertexArray (vertexArray);
|
|
|
|
GL.GenBuffers (1, out vertexBuffer);
|
|
GL.BindBuffer (BufferTarget.ArrayBuffer, vertexBuffer);
|
|
|
|
GL.BufferData (BufferTarget.ArrayBuffer, (IntPtr) (gCubeVertexData.Length * sizeof (float)), gCubeVertexData, BufferUsage.StaticDraw);
|
|
|
|
GL.EnableVertexAttribArray ((int) GLKVertexAttrib.Position);
|
|
GL.VertexAttribPointer ((int) GLKVertexAttrib.Position, 3, VertexAttribPointerType.Float, false, 24, 0);
|
|
|
|
GL.EnableVertexAttribArray ((int) GLKVertexAttrib.Normal);
|
|
GL.VertexAttribPointer ((int) GLKVertexAttrib.Normal, 3, VertexAttribPointerType.Float, false, 24, 12);
|
|
|
|
GL.Oes.BindVertexArray (0);
|
|
|
|
RandomizeBigCube ();
|
|
|
|
for (int i = 0; i< NumLittleCubes; i++)
|
|
littleCube[i] = bigCube;
|
|
|
|
timeOfLastRenderedFrame = CAAnimation.CurrentMediaTime();
|
|
}
|
|
|
|
public void RandomizeBigCube()
|
|
{
|
|
bigCube.Red = (minimums.Red + ((float) gen.NextDouble() * (maximums.Red - minimums.Red)));
|
|
bigCube.Green = (minimums.Green + ((float) gen.NextDouble() * (maximums.Green - minimums.Green)));
|
|
bigCube.Blue = (minimums.Blue + ((float) gen.NextDouble() * (maximums.Blue - minimums.Blue)));
|
|
bigCube.XAxis = (minimums.XAxis + ((float) gen.NextDouble() * (maximums.XAxis - minimums.XAxis)));
|
|
bigCube.YAxis = (minimums.YAxis + ((float) gen.NextDouble() * (maximums.YAxis - minimums.YAxis)));
|
|
bigCube.ZAxis = (minimums.ZAxis + ((float) gen.NextDouble() * (maximums.ZAxis - minimums.ZAxis)));
|
|
bigCube.Speed = (minimums.Speed + ((float) gen.NextDouble() * (maximums.Speed - minimums.Speed)));
|
|
bigCube.RotationRadians = (minimums.RotationRadians + ((float) gen.NextDouble() * (maximums.RotationRadians - minimums.RotationRadians)));
|
|
|
|
bigCubeDirections.Red = PositiveOrNegative();
|
|
bigCubeDirections.Green = PositiveOrNegative();
|
|
bigCubeDirections.Blue = PositiveOrNegative();
|
|
bigCubeDirections.XAxis = PositiveOrNegative();
|
|
bigCubeDirections.YAxis = PositiveOrNegative();
|
|
bigCubeDirections.ZAxis = PositiveOrNegative();
|
|
bigCubeDirections.Speed = PositiveOrNegative();
|
|
bigCubeDirections.RotationRadians = 0.0f;
|
|
}
|
|
|
|
public void UpdateCubes ()
|
|
{
|
|
double elapsedTime = CAAnimation.CurrentMediaTime () - timeOfLastRenderedFrame;
|
|
|
|
bigCube.Red = bigCube.Red + (bigCubeDirections.Red * deltas.Red * (float) elapsedTime);
|
|
if (bigCube.Red < minimums.Red || bigCube.Red > maximums.Red) {
|
|
bigCube.Red = Math.Max (minimums.Red, Math.Min (maximums.Red, bigCube.Red));
|
|
bigCubeDirections.Red *= -1;
|
|
}
|
|
|
|
bigCube.Green = bigCube.Green + (bigCubeDirections.Green * deltas.Green * (float) elapsedTime);
|
|
if (bigCube.Green < minimums.Green || bigCube.Green > maximums.Green) {
|
|
bigCube.Green = Math.Max (minimums.Green, Math.Min (maximums.Green, bigCube.Green));
|
|
bigCubeDirections.Green *= -1;
|
|
}
|
|
|
|
bigCube.Blue = bigCube.Blue + (bigCubeDirections.Blue * deltas.Blue * (float) elapsedTime);
|
|
if (bigCube.Blue < minimums.Blue || bigCube.Blue > maximums.Blue) {
|
|
bigCube.Blue = Math.Max (minimums.Blue, Math.Min (maximums.Blue, bigCube.Blue));
|
|
bigCubeDirections.Blue *= -1;
|
|
}
|
|
|
|
bigCube.XAxis = bigCube.XAxis + (bigCubeDirections.XAxis * deltas.XAxis * (float) elapsedTime);
|
|
if (bigCube.XAxis < minimums.XAxis || bigCube.XAxis > maximums.XAxis) {
|
|
bigCube.XAxis = Math.Max (minimums.XAxis, Math.Min (maximums.XAxis, bigCube.XAxis));
|
|
bigCubeDirections.XAxis *= -1;
|
|
}
|
|
|
|
bigCube.YAxis = bigCube.YAxis + (bigCubeDirections.YAxis * deltas.YAxis * (float) elapsedTime);
|
|
if (bigCube.YAxis < minimums.YAxis || bigCube.YAxis > maximums.YAxis) {
|
|
bigCube.YAxis = Math.Max (minimums.YAxis, Math.Min (maximums.YAxis, bigCube.YAxis));
|
|
bigCubeDirections.YAxis *= -1;
|
|
}
|
|
|
|
bigCube.ZAxis = bigCube.ZAxis + (bigCubeDirections.ZAxis * deltas.ZAxis * (float) elapsedTime);
|
|
if (bigCube.ZAxis < minimums.ZAxis || bigCube.Red > maximums.ZAxis) {
|
|
bigCube.ZAxis = Math.Max (minimums.ZAxis, Math.Min (maximums.ZAxis, bigCube.ZAxis));
|
|
bigCubeDirections.ZAxis *= -1;
|
|
}
|
|
|
|
bigCube.Speed = bigCube.Speed + (bigCubeDirections.Speed * deltas.Speed * (float) elapsedTime);
|
|
if (bigCube.Speed < minimums.Speed || bigCube.Speed > maximums.Speed) {
|
|
bigCube.Speed = Math.Max (minimums.Speed, Math.Min (maximums.Speed, bigCube.Speed));
|
|
bigCubeDirections.Speed *= -1;
|
|
}
|
|
|
|
bigCube.RotationRadians = UpdatedRotationRadians (bigCube.RotationRadians, bigCube.Speed, elapsedTime);
|
|
|
|
for (int i = 0; i < NumLittleCubes; i++)
|
|
littleCube [i].RotationRadians = UpdatedRotationRadians (littleCube [i].RotationRadians, littleCube [i].Speed, elapsedTime);
|
|
|
|
timeOfLastRenderedFrame = CAAnimation.CurrentMediaTime ();
|
|
}
|
|
|
|
public float UpdatedRotationRadians (float radians, float speed, double elapsedTime)
|
|
{
|
|
float speedInRadians = speed * (float) Math.PI * 2;
|
|
float radiansDelta = speedInRadians * (float) elapsedTime;
|
|
return (radians + radiansDelta) % ((float) Math.PI * 2);
|
|
}
|
|
|
|
public float PositiveOrNegative ()
|
|
{
|
|
bool temp = gen.Next (100) % 2 == 0;
|
|
return temp ? 1.0f : -1.0f;
|
|
}
|
|
}
|
|
}
|