using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tao.OpenGl;
#pragma warning disable 0618
using BauzoidNET.math;
using BauzoidNET.graphics;
using BauzoidNET.graphics.model;
using BauzoidNET.graphics.renderstates;
using BauzoidNET.graphics.texture;
namespace BauzoidNET
.graphics.sprite
{
public class TileBatch
: GraphicsObject
{
// Constants========================================================================================
public const int POSITION_COORD_PER_ELEMENT
= 3;
public const int NORMAL_COORD_PER_ELEMENT
= 3;
public const int COLOR_COORD_PER_ELEMENT
= 4;
public const int TEXCOORD_COORD_PER_ELEMENT
= 2;
public static readonly Vector4 WHITE_COLOR
= new Vector4
(1,
1,
1,
1);
public static readonly Vector4 BLACK_COLOR
= new Vector4
(0,
0,
0,
0);
public const int COORDS_PER_ELEMENT
= POSITION_COORD_PER_ELEMENT
+ COLOR_COORD_PER_ELEMENT
+ TEXCOORD_COORD_PER_ELEMENT
;
// Embedded Types===================================================================================
// Fields===========================================================================================
/** Number of vertices. */
private int mSize
= 0;
private float[] mVertices
= null;
private int mNumQuads
= 0;
// private SimpleGeometry mMesh = null;
private Texture mCurrentTexture
= null;
private bool mIsDrawing
= false;
private VertexStream mVertexStream
= null;
private IndexStream mIndexStream
= null;
// Methods==========================================================================================
public TileBatch
(Graphics graphics
)
: this(graphics,
250)
{
}
public TileBatch
(Graphics graphics,
int size
)
: base(graphics
)
{
mSize
= size
;
mVertexStream
= new VertexStream
(
getGraphics
(),
VertexStream
.StreamType.INTERLEAVED,
"Vertices",
new VertexAttribute
[]
{
new VertexAttribute
(VertexAttribute
.POSITION, POSITION_COORD_PER_ELEMENT,
0),
new VertexAttribute
(VertexAttribute
.COLOR, COLOR_COORD_PER_ELEMENT, POSITION_COORD_PER_ELEMENT
*sizeof(float)),
new VertexAttribute
(VertexAttribute
.TEXCOORD0, TEXCOORD_COORD_PER_ELEMENT,
(POSITION_COORD_PER_ELEMENT
+COLOR_COORD_PER_ELEMENT
)*sizeof(float))
},
false);
mIndexStream
= new IndexStream
(getGraphics
());
mVertices
= new float[size
* 4 * (COORDS_PER_ELEMENT
)];
//mCurrentVertex = 0;
mNumQuads
= 0;
// create indices as those will stay the same
int len
= size
* 6;
short[] indices
= new short[len
];
short j
= 0;
for (int i
= 0; i
< len
; i
+= 6, j
+= 4)
{
indices
[i
+ 0] = (short)(j
+ 0);
indices
[i
+ 1] = (short)(j
+ 1);
indices
[i
+ 2] = (short)(j
+ 2);
indices
[i
+ 3] = (short)(j
+ 0);
indices
[i
+ 4] = (short)(j
+ 2);
indices
[i
+ 5] = (short)(j
+ 3);
}
mIndexStream
.setData(indices
);
mIndexStream
.upload();
}
public void dispose
()
{
if (mVertexStream
!= null)
{
mVertexStream
.dispose();
mVertexStream
= null;
}
if (mIndexStream
!= null)
{
mIndexStream
.dispose();
mIndexStream
= null;
}
}
/** Initialize internal variables for a new batch. */
public void begin
()
{
if (mIsDrawing
)
return;
mIsDrawing
= true;
//mCurrentVertex = 0;
mNumQuads
= 0;
}
/** Stops collecting and renders what's left on the screen. */
public void end
()
{
if (!mIsDrawing
)
return;
if (mNumQuads
== 0)
return;
flush
();
}
/** Flush everything collected so far to screen and clear everything for new collection. */
public void flush
()
{
if (mCurrentTexture
== null)
return;
SpriteShader shader
= getGraphics
().getSpriteShader();
RenderStates rs
= getRenderStates
();
// bind VBO and upload geometry
mVertexStream
.setData(mVertices, COORDS_PER_ELEMENT, COORDS_PER_ELEMENT
* sizeof(float));
mVertexStream
.reupload();
// bind texture and render
rs
.pushModelMatrix();
{
rs
.model.identity();
// draw sprite
shader
.activate(mCurrentTexture, 1
.0f, WHITE_COLOR, BLACK_COLOR
);
{
rs
.blending.setEnabled(true);
rs
.culling.setEnabled(false);
rs
.activate();
{
mVertexStream
.activate();
mIndexStream
.activate();
//Gdx.gl20.glDrawElements(GL20.GL_TRIANGLES, mNumQuads*6, GL20.GL_UNSIGNED_SHORT, 0);
Gl
.glDrawElements(Gl
.GL_TRIANGLES, mNumQuads
* 6, Gl
.GL_UNSIGNED_SHORT,
0);
mVertexStream
.deactivate();
mIndexStream
.deactivate();
}
rs
.deactivate();
}
shader
.deactivate();
}
rs
.popModelMatrix();
//mCurrentVertex = 0;
mNumQuads
= 0;
}
/** Takes a sprite and uses its own properties to add it to the VBO. */
public void drawSprite
(SpriteInstance sprite
)
{
drawSprite
(sprite, sprite
.transform);
}
/** Takes a sprite and sprite properties and adds it to the VBO. */
public void drawSprite
(SpriteInstance sprite, SpriteTransform param
)
{
if (!isDrawing
())
return;
if (sprite
.getSprite().getTexture() != mCurrentTexture
)
flush
();
if ((mNumQuads
+1) > mSize
)
flush
();
mCurrentTexture
= sprite
.getSprite().getTexture();
// transform quad vertices based on sprite's properties
SpriteRegion r
= sprite
.getSpriteRegion(); //sprite.getSprite().getRegion(sprite.getRegionIndex());
// bottom left and top right corner points relative to origin
float worldOriginX
= param
.x + param
.pivotX;
float worldOriginY
= param
.y + param
.pivotY;
float fx
= -param
.pivotX;
float fy
= -param
.pivotY;
float fx2
= param
.w - param
.pivotX;
float fy2
= param
.h - param
.pivotY;
// construct corner points, start from top left and go counter clockwise
float p1x
= fx
;
float p1y
= fy
;
float p2x
= fx
;
float p2y
= fy2
;
float p3x
= fx2
;
float p3y
= fy2
;
float p4x
= fx2
;
float p4y
= fy
;
float x1
;
float y1
;
float x2
;
float y2
;
float x3
;
float y3
;
float x4
;
float y4
;
// rotate
if (param
.angle != 0)
{
float cos
= MathUtil
.cos(param
.angle);
// Angle is CCW
float sin
= -MathUtil
.sin(param
.angle);
x1
= cos
* p1x
- sin
* p1y
;
y1
= sin
* p1x
+ cos
* p1y
;
x2
= cos
* p2x
- sin
* p2y
;
y2
= sin
* p2x
+ cos
* p2y
;
x3
= cos
* p3x
- sin
* p3y
;
y3
= sin
* p3x
+ cos
* p3y
;
x4
= x1
+ (x3
- x2
);
y4
= y3
- (y2
- y1
);
}
else
{
x1
= p1x
;
y1
= p1y
;
x2
= p2x
;
y2
= p2y
;
x3
= p3x
;
y3
= p3y
;
x4
= p4x
;
y4
= p4y
;
}
x1
+= worldOriginX
- param
.pivotX;
y1
+= worldOriginY
- param
.pivotY;
x2
+= worldOriginX
- param
.pivotX;
y2
+= worldOriginY
- param
.pivotY;
x3
+= worldOriginX
- param
.pivotX;
y3
+= worldOriginY
- param
.pivotY;
x4
+= worldOriginX
- param
.pivotX;
y4
+= worldOriginY
- param
.pivotY;
float u
= r
.left;
float v
= r
.top;
float u2
= r
.right;
float v2
= r
.bottom;
if (param
.mirrorX)
{
float tmp
= u
;
u
= u2
;
u2
= tmp
;
}
if (param
.mirrorY)
{
float tmp
= v
;
v
= v2
;
v2
= tmp
;
}
// add vertices to buffer
int n
= mNumQuads
* 4 * (COORDS_PER_ELEMENT
);
mVertices
[n
++] = x1
;
mVertices
[n
++] = y1
;
mVertices
[n
++] = 0;
mVertices
[n
++] = sprite
.color.x;
mVertices
[n
++] = sprite
.color.y;
mVertices
[n
++] = sprite
.color.z;
mVertices
[n
++] = sprite
.color.w;
mVertices
[n
++] = u
;
mVertices
[n
++] = v
;
//mVertices[n++] = texCoords[0];
//mVertices[n++] = texCoords[1];
mVertices
[n
++] = x2
;
mVertices
[n
++] = y2
;
mVertices
[n
++] = 0;
mVertices
[n
++] = sprite
.color.x;
mVertices
[n
++] = sprite
.color.y;
mVertices
[n
++] = sprite
.color.z;
mVertices
[n
++] = sprite
.color.w;
mVertices
[n
++] = u
;
mVertices
[n
++] = v2
;
//mVertices[n++] = texCoords[2];
//mVertices[n++] = texCoords[3];
mVertices
[n
++] = x3
;
mVertices
[n
++] = y3
;
mVertices
[n
++] = 0;
mVertices
[n
++] = sprite
.color.x;
mVertices
[n
++] = sprite
.color.y;
mVertices
[n
++] = sprite
.color.z;
mVertices
[n
++] = sprite
.color.w;
mVertices
[n
++] = u2
;
mVertices
[n
++] = v2
;
//mVertices[n++] = texCoords[4];
//mVertices[n++] = texCoords[5];
mVertices
[n
++] = x4
;
mVertices
[n
++] = y4
;
mVertices
[n
++] = 0;
mVertices
[n
++] = sprite
.color.x;
mVertices
[n
++] = sprite
.color.y;
mVertices
[n
++] = sprite
.color.z;
mVertices
[n
++] = sprite
.color.w;
mVertices
[n
++] = u2
;
mVertices
[n
++] = v
;
//mVertices[n++] = texCoords[6];
//mVertices[n++] = texCoords[7];
//mCurrentVertex += 4;
mNumQuads
++;
}
// Getters/Setters==================================================================================
private bool isDrawing
() { return mIsDrawing
; }
}
}