Add background image tileset support, some demo
121
OpenTK-Test/JustTheBasics/BGTile.cs
Normal file
@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace JustTheBasics
|
||||
{
|
||||
class BGTile
|
||||
{
|
||||
// Member variables
|
||||
// Var for storing position (in pixels) on the screen
|
||||
public Vector3 Position = Vector3.Zero;
|
||||
// Store the factor by which the image is magnified or shrunk
|
||||
public Vector3 Scale = Vector3.One;
|
||||
|
||||
// Number of vertices in a Quad
|
||||
public int VertCount = 4;
|
||||
// Number of indices for each array associated with this object
|
||||
public int IndiceCount = 4;
|
||||
// Number of colors specified for vertices (only when not drawing an image)
|
||||
public int ColorDataCount = 4;
|
||||
|
||||
// OpenTK Matrices pertaining to storing the Sprite's properties as seen by the viewer
|
||||
public Matrix4 ModelMatrix = Matrix4.Identity;
|
||||
public Matrix4 ViewProjectionMatrix = Matrix4.Identity;
|
||||
public Matrix4 ModelViewProjectionMatrix = Matrix4.Identity;
|
||||
|
||||
// Variables pertaining to whether an image texture is applied, and what it is
|
||||
public bool IsTextured = true;
|
||||
public int TextureID;
|
||||
public int TextureCoordsCount;
|
||||
|
||||
// Variable to determine if the background image should be tiled in case it is too
|
||||
// small for the window.
|
||||
public bool repeat = true;
|
||||
// Variables to hold the speed at which backgrounds should scroll as the camera moves
|
||||
public float scrollX = 0.0f;
|
||||
public float scrollY = 0.0f;
|
||||
|
||||
// Variable for tile size
|
||||
public int tSize;
|
||||
// Variable for tile index
|
||||
public Vector2 index;
|
||||
|
||||
// Additional variables for scaling to viewport
|
||||
public int Height = 0;
|
||||
public int Width = 0;
|
||||
|
||||
// Function to return the coordinates of the quad's corners, in normalized screen space. (-1 ~ 1)
|
||||
public Vector3[] GetVerts()
|
||||
{
|
||||
return new Vector3[] { new Vector3(-1f, -1f, 0f),
|
||||
new Vector3( 1f, -1f, 0f),
|
||||
new Vector3( 1f, 1f, 0f),
|
||||
new Vector3( -1f, 1f, 0f)};
|
||||
}
|
||||
|
||||
// Overload of above that takes window dimensions so the sprite is scaled to viewport
|
||||
public Vector3[] GetVerts(float wWidth, float wHeight)
|
||||
{
|
||||
return new Vector3[] { new Vector3(-1f, -1f, 0f),
|
||||
new Vector3( -1f + (tSize/wWidth), -1f, 0f),
|
||||
new Vector3( -1f + (tSize/wWidth), -1f + (tSize/wHeight), 0f),
|
||||
new Vector3( -1f, -1f + (tSize/wHeight), 0f)};
|
||||
}
|
||||
|
||||
// Generate the int indices for a large array containing the vertices of every quad in the scene.
|
||||
// The reason for this is that OpenTK uses unique indices for every visible object. Hence,
|
||||
// we need to factor in an offset from the total number of verts already processed, and
|
||||
// thereby prevent draw errors from OpenTK.
|
||||
public int[] GetIndices(int offset = 0)
|
||||
{
|
||||
int[] inds = new int[] {
|
||||
0, 1, 2, 3
|
||||
};
|
||||
|
||||
if (offset != 0)
|
||||
{
|
||||
for (int i = 0; i < inds.Length; i++)
|
||||
{
|
||||
inds[i] += offset;
|
||||
}
|
||||
}
|
||||
|
||||
return inds;
|
||||
}
|
||||
|
||||
// Return the coords for the corners of the texture as related to the quad's coords.
|
||||
// This function assumes covering the whole quad.
|
||||
public Vector2[] GetTextureCoords()
|
||||
{
|
||||
return new Vector2[]
|
||||
{
|
||||
new Vector2((tSize*index.X)/Width, (tSize*index.Y)/Height),
|
||||
new Vector2(((tSize*index.X) + tSize)/Width, (tSize*index.Y)/Height),
|
||||
new Vector2(((tSize*index.X) + tSize)/Width, ((tSize*index.Y) + tSize)/Height),
|
||||
new Vector2((tSize*index.X)/Width, ((tSize*index.Y) + tSize)/Height)
|
||||
};
|
||||
}
|
||||
|
||||
// Get the color of each vertex. These will blend in the intermediate space.
|
||||
public Vector3[] GetColorData()
|
||||
{
|
||||
return new Vector3[] { new Vector3(1f, 0f, 0f),
|
||||
new Vector3( 0f, 0f, 1f),
|
||||
new Vector3( 0f, 1f, 0f),
|
||||
new Vector3( 1f, 1f, 1f)};
|
||||
}
|
||||
|
||||
// Update the projection to the camera based on position and scale.
|
||||
public void CalculateModelMatrix()
|
||||
{
|
||||
ModelMatrix = Matrix4.CreateScale(Scale) * Matrix4.CreateTranslation(Position);
|
||||
}
|
||||
}
|
||||
}
|
Before (image error) Size: 7.3 KiB After (image error) Size: 34 KiB |
@ -47,6 +47,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Background.cs" />
|
||||
<Compile Include="BGTile.cs" />
|
||||
<Compile Include="Camera.cs" />
|
||||
<Compile Include="GameObject.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
@ -83,6 +84,9 @@
|
||||
<Content Include="LifeIcon.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="NoImage.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Tile_Set_2.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
Before (image error) Size: 405 B After (image error) Size: 494 B |
BIN
OpenTK-Test/JustTheBasics/NoImage.png
Normal file
After (image error) Size: 169 B |
@ -50,6 +50,9 @@ namespace JustTheBasics
|
||||
// Dictionary to store background images
|
||||
Dictionary<string, Background> BGs = new Dictionary<string, Background>();
|
||||
|
||||
// Dictionary for background tiles
|
||||
Dictionary<string, BGTile> BGTiles = new Dictionary<string, BGTile>();
|
||||
|
||||
// Default constructor that sets window size to 512x512 and adds some antialiasing (the GraphicsMode part)
|
||||
public Game() : base(800, 600, new OpenTK.Graphics.GraphicsMode(32, 24, 0, 4))
|
||||
{
|
||||
@ -85,11 +88,11 @@ namespace JustTheBasics
|
||||
tc.TextureID = textures["LifeIcon.png"];
|
||||
|
||||
// Create a new GameObject
|
||||
Vector2 startPos = new Vector2(16, 16);
|
||||
Vector2[] spawn = new Vector2[] { new Vector2(0, 32), new Vector2(32, 32), new Vector2(32, 0) };
|
||||
Vector2 startPos = new Vector2(64, 64);
|
||||
Vector2[] spawn = new Vector2[] { new Vector2(0, 64), new Vector2(64, 64), new Vector2(64, 0) };
|
||||
|
||||
float[] map = new float[] { 0f, 0f, Width, Height };
|
||||
GameObject objPlayer = new GameObject("Player", startPos, spawn, map, 1.0f, 0f, true, tc);
|
||||
GameObject objPlayer = new GameObject("Player", startPos, spawn, map, 4.0f, 0f, true, tc);
|
||||
|
||||
// Add the sprite to our list of active Sprites
|
||||
objects[1].Add(objPlayer);
|
||||
@ -106,18 +109,53 @@ namespace JustTheBasics
|
||||
|
||||
// Create a new GameObject
|
||||
Vector2 sPos2 = new Vector2(128, 128);
|
||||
Vector2[] spawnBrick = new Vector2[] { new Vector2(0, 64), new Vector2(64, 64), new Vector2(64, 0) };
|
||||
Vector2[] spawnBrick = new Vector2[] { new Vector2(0, 128), new Vector2(128, 128), new Vector2(128, 0) };
|
||||
|
||||
GameObject objBricks = new GameObject("Bricks", sPos2, spawnBrick, map, 0.0f, 0.0f, true, bc);
|
||||
|
||||
// Add the sprite to our list of active Sprites
|
||||
objects[2].Add(objBricks);
|
||||
|
||||
// Make some invisible walls
|
||||
int wallX = 0;
|
||||
int wallY = 0;
|
||||
textures.Add("NoImage.png", loadImage("NoImage.png", out wallX, out wallY, true));
|
||||
for (int i = 0; i < 1600; i += 64)
|
||||
{
|
||||
Sprite ws = new Sprite();
|
||||
ws.Width = wallX;
|
||||
ws.Height = wallY;
|
||||
ws.TextureID = textures["NoImage.png"];
|
||||
Vector2[] spawnWall = new Vector2[] { new Vector2(0, 64), new Vector2(64, 64), new Vector2(64, 0) };
|
||||
GameObject wall = new GameObject("Wall" + i.ToString(), new Vector2(i, 0f), spawnWall, map, 0f, 0f, true, ws);
|
||||
objects[2].Add(wall);
|
||||
}
|
||||
|
||||
// Create a background
|
||||
Background bg = new Background();
|
||||
textures.Add("circuit.png", loadImage("CircuitBOTTOM.png", bg, true));
|
||||
bg.TextureID = textures["circuit.png"];
|
||||
BGs.Add("circuit", bg);
|
||||
|
||||
// Create background tiles
|
||||
int tilesetSizeX = 0;
|
||||
int tilesetSizeY = 0;
|
||||
textures.Add("Tile_Set_2.png", loadImage("Tile_Set_2.png", out tilesetSizeX, out tilesetSizeY, true));
|
||||
for (int i = 0; i < 1600; i += 64)
|
||||
{
|
||||
BGTile bgt = new BGTile();
|
||||
bgt.Width = tilesetSizeX;
|
||||
bgt.Height = tilesetSizeY;
|
||||
bgt.TextureID = textures["Tile_Set_2.png"];
|
||||
bgt.Position = new Vector3(i/(float)Width, 0, 0);
|
||||
bgt.index = new Vector2((i/64)%2 + 1, 1);
|
||||
bgt.tSize = 64;
|
||||
BGTiles.Add("Tile"+i.ToString(), bgt);
|
||||
// Update the matrix used to calculate the Sprite's visuals
|
||||
bgt.CalculateModelMatrix();
|
||||
// Offset it by our viewport matrix (for things like scrolling levels)
|
||||
bgt.ModelViewProjectionMatrix = bgt.ModelMatrix;// * ortho;
|
||||
}
|
||||
}
|
||||
|
||||
// This function overrides the base OnLoad function
|
||||
@ -168,6 +206,16 @@ namespace JustTheBasics
|
||||
vertcount += bg.VertCount;
|
||||
texcoords.AddRange(bg.GetTextureCoords());
|
||||
}
|
||||
// Set up rendering for background tiles
|
||||
foreach (BGTile bgt in BGTiles.Values)
|
||||
{
|
||||
// Populate the previously defined lists
|
||||
verts.AddRange(bgt.GetVerts(Width, Height).ToList());
|
||||
inds.AddRange(bgt.GetIndices(vertcount).ToList());
|
||||
colors.AddRange(bgt.GetColorData().ToList());
|
||||
vertcount += bgt.VertCount;
|
||||
texcoords.AddRange(bgt.GetTextureCoords());
|
||||
}
|
||||
|
||||
// Stack for LIFO behavior in drawing sprites
|
||||
Stack<GameObject> objLists = new Stack<GameObject>();
|
||||
@ -296,6 +344,29 @@ namespace JustTheBasics
|
||||
indiceat += bg.IndiceCount;
|
||||
}
|
||||
|
||||
// Loop over every background tile and render it
|
||||
foreach (BGTile bgt in BGTiles.Values)
|
||||
{
|
||||
// Tell OpenTK to associate the given texture to the VBO we're drawing
|
||||
GL.BindTexture(TextureTarget.Texture2D, bgt.TextureID);
|
||||
|
||||
// Allow tiling of images
|
||||
|
||||
// Send our projection matrix to the GLSL shader
|
||||
GL.UniformMatrix4(shaders[activeShader].GetUniform("modelview"), false, ref bgt.ModelViewProjectionMatrix);
|
||||
|
||||
// If shader uses textures, send the image to the shader code for processing
|
||||
if (shaders[activeShader].GetAttribute("maintexture") != -1)
|
||||
{
|
||||
GL.Uniform1(shaders[activeShader].GetAttribute("maintexture"), bgt.TextureID);
|
||||
}
|
||||
|
||||
// Draw a square/rectangle
|
||||
GL.DrawElements(BeginMode.Quads, bgt.IndiceCount, DrawElementsType.UnsignedInt, indiceat * sizeof(uint));
|
||||
// Increment our index counter by the number of indices processed
|
||||
indiceat += bgt.IndiceCount;
|
||||
}
|
||||
|
||||
// Loop over every GameObject in the game
|
||||
// First put the highest-draw layer objects at the bottom so they draw last
|
||||
// Stack for LIFO behavior in drawing sprites
|
||||
@ -439,6 +510,24 @@ namespace JustTheBasics
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Another overload, does the same as above, but also takes two ints
|
||||
// into as arguments, so that it can return the height and width of the sprite.
|
||||
int loadImage(string filename, out int x, out int y, bool tile = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
Bitmap file = new Bitmap(filename);
|
||||
x = file.Width;
|
||||
y = file.Height;
|
||||
return loadImage(file, tile);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Small class that basically is a Main() function and just runs the game.
|
||||
|
Before (image error) Size: 6.7 KiB After (image error) Size: 8.7 KiB |
Before (image error) Size: 7.3 KiB After (image error) Size: 34 KiB |
Before (image error) Size: 405 B After (image error) Size: 494 B |
BIN
OpenTK-Test/JustTheBasics/bin/Debug/NoImage.png
Normal file
After (image error) Size: 169 B |
Before (image error) Size: 6.7 KiB After (image error) Size: 8.7 KiB |