SpikedSoftware

Bashing MKV’s into M2TS

by Dean Thomas on Apr.04, 2009, under Ubuntu

If, like me, you have alot of MKV’s lying around on your machine, my PS3 will play them using the PS3 Media Server (which is awesome by the way, nothing comes close as far as i’m concerned) as it will use mplayer or tsMuxeR to transcode them on the fly to the PS3.

But, why bother? Why put my PC through the stress of re-encoding video on the fly, just so my PS3 can play them. MKV is just a container, it contains a perfectly playable Mpeg stream and a DD 5.1 sound track, that the ps3 can play flawlessly, it just doesn’t understand the MKV format (yet, come on Sony…).

So, let’s just remux the video to an M2TS, as these can be played by the PS3. Remuxing means, taking the audio/video stream we are after from the file, and not re-encoding them at all, just repackaging them. As i said before, MKV is just a container, it is a method of storing video/audio content.

First off, you will need some MKV tools, lets get those quickly.

% sudo apt-get install mkvtoolnix

To remux, you will need a tool called tsMuxeR, which is freeware, thankfully. It has also been recently updated to include the up-till-now windows only gui. Which is great!

So, let’s download it, fire up a terminal of your choice, and lets get cracking. We’ll be working in your home folder first.

% cd ~/
% mkdir tsmuxer
% cd tsmuxer
% wget http://www.smlabs.net/tsMuxer/tsMuxeR_1.8.35\(b\).tar.gz
% tar zxvf ts*.gz

Now, you will have a few files in that folder, we are only interested in one of them for this post, but feel free to have a play with the GUI. Let’s move the tsMuxeR into the bin folder so our script we’re about to write will be able to access it.

% sudo mv tsMuxeR /usr/bin/

Now, tsMuxeR, should be accessible from anywhere on your machine. Test it just by typing tsMuxeR and it should spit out the version number, and some usage information.

So lets get onto our script, we want to be able to convert any MKVs, to M2TS, whilst also pulling out the language that we speak, with the best track. I.e. if there is a 5.1 channel track, use that instead of stereo.

This is a script that i have modified that was written a while ago, but it does the job, quite well too.

# /bin/bash
# - a simple wrapper around the tsmuxeR
# Creates a m2ts from a "standard" mkv (assuming video is MPEG4, and sound is AC3 or DTS)
#
# v0.1 initial version
# v0.2 added DTS support
# v0.3 changed to tsmuxer linux version + added multiple audio lang support
#
# Usage: mkvtom2ts filename.mkv
#
 
# Change this variable here, to change the languages it will strip from the MKV video.
AUDIO_LANGS="und eng"
 
#Loop through all MKVs in the current directory
for f in ./*.mkv
do
BASENAME=$(basename "$f" .mkv)
DEST_FILE=$BASENAME.m2ts
 
MPEG4_TRACK_NO=`mkvinfo "$f" | grep V_MPEG4/ISO/AVC -B10 | grep Track\ number\:\ | awk '{ print $5 }'`
 
for AUDIO_LANG in $AUDIO_LANGS
do
AC3_TRACK_NO=`mkvinfo "$f" | grep A_AC3 -B10 -C3 | grep Language\:\ $AUDIO_LANG -B13 | grep Track\ number\:\ | awk '{ print $5 }'`
DTS_TRACK_NO=`mkvinfo "$f" | grep A_DTS -B10 -C3 | grep Language\:\ $AUDIO_LANG -B13 | grep Track\ number\:\ | awk '{ print $5 }'`
if [ -n "$AC3_TRACK_NO" -o -n "$DTS_TRACK_NO" ]
then
break
fi
done
 
echo "Video(V_MPEG4/ISO/AVC) track no : $MPEG4_TRACK_NO"
echo "Audio(A_AC3) $AUDIO_LANG track no      : $AC3_TRACK_NO"
echo "Audio(A_DTS) $AUDIO_LANG track no      : $DTS_TRACK_NO"
 
#audio ac3->direct muxing
if [[ $AC3_TRACK_NO -gt "0" ]]
then
echo "Found ac3 track, muxing directly..."
rm -f mux.meta
echo "MUXOPT --no-pcr-on-video-pid --new-audio-pes --vbr" >> mux.meta
echo "V_MPEG4/ISO/AVC, "$f", level=4.1, insertSEI, contSPS, track=$MPEG4_TRACK_NO, lang=eng.meta" >> mux.meta
echo "A_AC3, "$f", track=$AC3_TRACK_NO, lang=eng" >> mux.meta
tsMuxeR mux.meta $DEST_FILE
rm -f mux.meta
else
if [[ $DTS_TRACK_NO -gt "0" ]]
then
echo "No ac3 but dts, converting to ac3.."
mkvextract tracks "$f" $DTS_TRACK_NO:"$BASENAME.dts" $MPEG4_TRACK_NO:"$BASENAME.mpeg4"
dcadec -r -o wavall "$BASENAME.dts" > "$BASENAME.wav"
aften "$BASENAME.wav" "$BASENAME.ac3"
echo "Muxing..."
rm -f mux.meta
echo "MUXOPT --no-pcr-on-video-pid --new-audio-pes --vbr" >> mux.meta
echo "V_MPEG4/ISO/AVC, "$BASENAME.mpeg4", level=4.1, insertSEI, contSPS, track=1, lang=eng" >> mux.meta
echo "A_AC3, "$BASENAME.ac3", track=1, lang=eng" >> mux.meta
tsMuxeR mux.meta $DEST_FILE
rm -f mux.meta $BASENAME.dts $BASENAME.wav $BASENAME.ac3 $BASENAME.mpeg4
else
echo "No ac3 or dts, exiting..."
fi
fi
 
if (disaster-condition)
then
#Abandon the loop.
break
fi
 
done

Have a quick read over the script, don’t worry about not understanding it, it’s not important, so long as it works :)

Lets make this file, and put it somewhere we can always use it.

% gedit allmkv2m2ts

Now copy all the code above which does the converting, and paste it into that file, then save and close gedit.

% sudo mv allmkv2m2ts /usr/bin/mkvall2m2ts
% sudo chmod 777 /usr/bin/allmkv2m2ts

It is now in the bin folder, so can be accessed anywhere, it can also used and edited by anyone.

And thats it. Now navigate yourself to your folder with all the MKVs in the root, and just type..

% allmkv2m2ts

Asif by magic, it should now start re-muxing all your MKVs to M2TS.

Please feel free to comment, and if you wrote the original script, please contact me and i will link to you.

Leave a Comment :, , , , , , more...

Blank screen, without a paddle…

by Dean Thomas on Jan.09, 2009, under Pong Tutorial

Well, if you followed the previous tutorial, we have a nice window, with nothing at all related to Pong inside it. Let’s create some paddles!

OK, So, sticking with the whole ‘modular’ process we have followed to so far, we aren’t just going to render a quad and throw a texture on it. We need to create an Entity Class, which will be the base class for any Entity (Ball, Paddles, Walls) we are going to need to use. Again, i know it’s a bit of hassle, but it’s all for the greater good, it means we’ll be able to add objects in and have certain standard functionality for any object, making rendering them much easier. Let’s see the class definition.

Entity.h

#ifndef ENTITY_H_
#define ENTITY_H_
 
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
 
#include <GL/glew.h>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
 
//This isn't actually used yet really, but we will use it later, for checking what type of entity we are
enum ObjectType
{
	Type_Object, Type_Wall, Type_Ball, Type_Paddle, Type_Goal
};
 
class Entity
{
protected:
	float _width, _height;
	GLuint _texture;
	GLfloat _r, _g, _b;
	ObjectType _type;
 
	//Load up a bitmap from the provided filename so we can texture the quad with it.
	void CreateTextureFromFile(const char *filename);
 
	//Run a check to see if two entitys are colliding
	bool CollideBoundingBox(SDL_Rect a, SDL_Rect b);
 
public:
	float xVel, yVel;
	float _x, _y, _z;
 
	Entity();
 
	//Overrideable, so we know that Type of object this is (Enum ObjectType)
	virtual ObjectType Type();
 
	//Set the type of this object
	void SetType(ObjectType theType);
 
	//Check against another Entity if there is a collision occuring
	bool IsColliding(Entity *targetObject);
 
	//Default render method, just renders a quad
	void Render();
 
	//Initialise this Entity, with the following values...
	void Initialise(float width, float height, float x, float y);
	void Initialise(float width, float height, float x, float y, const char *texturelocation);
 
	//Give it a pretty colour? Not required...
	void SetColour(GLfloat r, GLfloat g, GLfloat b);
};
#endif /* ENTITY_H_ */

And there it is, all the methods have been commented enough to make them clear. They should be more understandable when we go through the declaration.

Now this is going to be quite long, as we are also going to support texturing in this class. So i will be taking you through that too.

First off, create a file in the same folder (Pong/src) called Entity.cpp, this is where all the logic will be held! For now, just throw this code into it, it should be fairly understandable as is.

Entity.cpp

#include "Entity.h"
 
Entity::Entity()
{
        //Initialise all the variables we are going to use...
	this-&gt;_x = this-&gt;_y = this-&gt;xVel = this-&gt;yVel = this-&gt;_r = this-&gt;_g = this-&gt;_b = 0.0f;
	this-&gt;_texture = 0;
}

Let’s get onto the definitions of the fun stuff! I say we start with Initialise, as it’s really the first method(s) that get called. So let’s see it.

void Entity::Initialise(float width, float height, float x, float y)
{
        //Literally just set the variables, these won't get used again until render.
	_width = width;
	_height = height;
	_x = x;
	_y = y;
}
 
void Entity::Initialise(float width, float height, float x, float y, const char *texturelocation)
{
        //Call the other Initialise method, just so we can set the values
	this-&gt;Initialise(width, height, x, y);
 
        ///Create a texture, using the textureLocation variable passed in
	CreateTextureFromFile(texturelocation);
}
 
void Entity::SetColour(GLfloat r, GLfloat g, GLfloat b)
{
	this->_r = r;
	this->_g = g;
	this->_b = b;
}

Now, any bright spark will know this won’t now compile, because i haven’t given you the definition for CreateTextureFromFile, well thats next, so be patient! ;) It’s quite long, so i have commented it in detail…

void Entity::CreateTextureFromFile(const char *filename)
{
	//We will use this Surface to load the image onto, before we create a texture out of it.
	SDL_Surface *surface; 
 
	//This will store the texture format for OpenGL, i.e. RGB, RGBA, BGR, etc
	GLenum texture_format;
 
	//This stores how many colours we have in the image, i.e. if it's only got RGB, we have 3
	GLint nOfColors;
 
	//Lets load up the image provided by the filename parameter
	if ((surface = SDL_LoadBMP(filename)))
	{
		//Whoo, we have loaded it, let's find it's format!
		nOfColors = surface-&gt;format-&gt;BytesPerPixel;
 
		//Do we have 4 colours? Red, Green, Blue and Alpha
		if (nOfColors == 4)
		{
			//Yes, which order is it? Red First?
			if (surface-&gt;format-&gt;Rmask == 0x000000ff)
				texture_format = GL_RGBA;
			else
				texture_format = GL_BGRA;
		}
		else if (nOfColors == 3)
		{
			//Oh, we only have 3 colours? OK, again, which order are those 3 colours in?
			if (surface-&gt;format-&gt;Rmask == 0x000000ff)
				texture_format = GL_RGB;
			else
				texture_format = GL_BGR;
		}
		else
			printf("warning: the image is not truecolor..  this will probably breakn");
 
		// Have OpenGL generate a texture object handle for us, using our _texture Member variable, so we always have access to it
		glGenTextures(1, &amp;_texture);
 
		// Bind the texture object to our _textureMember variable
		glBindTexture(GL_TEXTURE_2D, _texture);
 
		// Set a few parameters on our Texture, so it displays as we want it to.
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
 
		// Set all the image data of the texture, here we set it's width, it's height, the format, and the actual data (surface-&gt;pixels)
		glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, surface-&gt;w, surface-&gt;h, 0, texture_format, GL_UNSIGNED_BYTE, surface-&gt;pixels);
	}
	else
	{
		//General error message if file could not be found
		std::cout &lt;&lt; "SDL could not load " &lt;&lt; filename &lt;&lt; ": " &lt;&lt; SDL_GetError() &lt;&lt; std::endl;
		SDL_Quit();
	}
 
	// Free the SDL_Surface only if it was successfully created
	if (surface)
	{
		//Free the memory used by the surface, as we have now loaded all the data up into OpenGL, it has it's own copy of the image in memory
		SDL_FreeSurface(surface);
	}
}

So, now we have can create an Entity, give it a texture, but we still can’t see it? Damn, i guess we should render it then.

void Entity::Render()
{
	//If we have an xVelocity or a yVelocity, then increment the X or Y position based on their velocity
	if (xVel != 0 || yVel != 0)
	{
		_x += this-&gt;xVel;
		_y += this-&gt;yVel;
	}
 
	//Check to see if we have a texture loaded up, if we do, then enable texturing and bind the texture, so that the next thing
	//we render with texturing, it will get this texture.
	if (_texture != 0)
	{
		//Enable Texturing
		glEnable(GL_TEXTURE_2D);
		//Bind the Texture to this object
		glBindTexture(GL_TEXTURE_2D, _texture);
	}
 
	//Stack the current settings for colour, so we can set the colour for this object, then pop the settings back when we are done
	glPushAttrib(GL_CURRENT_BIT);
 
	//Draw this object the correct colour, notice we set the _r, _g, _b color. This WILL effect the colour of your textures.
	glColor3f(_r, _g, _b);
 
	//Move the object to the correct location in space, we are only working in 2D so don't need to worry about the Z Value
	glTranslatef(_x, _y, 0);
 
	//Tell OpenGL we want to render a quad, which is a 4 sided polygon
	glBegin(GL_QUADS);
 
	//Now, here we need to check to see if we loaded up a texture, if we did then we need to tell opengl how to render the texture
	//i.e. where the top left is. I won't comment the others, as this one should explain them all. We set 0,0 because that is the
	//upper left of the quad, and that is how we want our Image to appear. We could render it upside down of course, but thats silly.
	if (_texture != 0)
		glTexCoord2i(0, 0);
 
	//So, now we have told opengl where to render our texture, we need to give it something to render it onto. We want to create vertex
	//which is just a point in 3d space, of course as we are creating a quad, we need to specify 4 of them. This is the top left corner
	//of the box, we next do the bottom left, then the bottom right, then the top right. OGL will then render that as a 4 sided polygon.
	glVertex3f(0, 0, 0);
 
	//Texturing again
	if (_texture != 0)
		glTexCoord2i(0, 1);
 
	//Bottom Left Corner, see how we specify the height. This will create an object which is _height pixels high.
	glVertex3f(0, _height, 0);
 
	//Texturing again
	if (_texture != 0)
		glTexCoord2i(1, 1);
 
	//Bottom left, again, with the height, also now with the width
	glVertex3f(_width, _height, 0);
 
	//Texturing again
	if (_texture != 0)
		glTexCoord2i(1, 0);
 
	//Now for the top right, just need to tell it the width
	glVertex3f(_width, 0, 0);
	glEnd();
 
	//Pop the colour settings back from the stack
	glPopAttrib();
 
	//Disable Texturing again, so nothing else gets this texture applied to them.
	if (_texture != 0)
		glDisable(GL_TEXTURE_2D);
}

There is the beast, this will now allow us to render a 2D object (technically it is a 3d object) onto the screen, with a designated texture. Should we so with, this is just preparation for the future, we aren’t going to be texturing anything in this tutorial

So, we can create an entity, give it a texture, and now render it, what else is there?! Well, we need to know when two Entity’s are touching each other, otherwise how will we know when we’ve scored a goal? Or even worse, the ball won’t bounce off the wall and it’ll just float into space, and then no-one wins. And nobody likes a draw.

Let’s do some collision detection, it’s only simple 2D stuff. This function was taken from GPWiki, which is brilliant for Game Programming. This is the exact link to the article i used. I didn’t see the point in-reinventing the wheel, even though it is a very simple wheel.

Here’s the definition of the Collision methods.

bool Entity::CollideBoundingBox(SDL_Rect a, SDL_Rect b)
{
	if (b.x + b.w &lt; a.x)
		return false;
	if (b.x &gt; a.x + a.w)
		return false;
 
	if (b.y + b.h &lt; a.y)
		return false;
	if (b.y &gt; a.y + a.h)
		return false;
 
	return true; //bounding boxes intersect
}
 
bool Entity::IsColliding(Entity *targetObject)
{
        //This isn't the most optimal way of doing this, but it does the trick for pong. We just create two rectangles
        //for this entity and the target one, so we can see if they are overlapping
	SDL_Rect thisRect;
	thisRect.h = this-&gt;_height;
	thisRect.w = this-&gt;_width;
	thisRect.x = this-&gt;_x;
	thisRect.y = this-&gt;_y;
 
	SDL_Rect targetRect;
	targetRect.h = targetObject-&gt;_height;
	targetRect.w = targetObject-&gt;_width;
	targetRect.x = targetObject-&gt;_x;
	targetRect.y = targetObject-&gt;_y;
 
        //Run the check, to see if they are colliding
	return CollideBoundingBox(thisRect, targetRect);
}

Now we can check to see if two objects are colliding. I.e. the Ball with the Wall, or the Ball with a paddle.

Here are the other two methods, that are really simple and won’t actually get used just yet. This again, is for future use. It’s just for storing and retrieving the Entity’s type, i.e. Ball

ObjectType Entity::Type()
{
	return _type;
}
 
void Entity::SetType(ObjectType theType)
{
	_type = theType;
}

Right, let’s get a paddle on our screen, that’s enough preperation! Note: Don’t forget, we need to add this class to the Makefiles! Don’t remember how? Follow the previous tutorial, but instead of adding Pong.o we want Entity.o. I will attach the entire folder at the end so you could just take those makefiles.

In your Pong.h, you will now need to create a Two Entity instances and include the Entity header.

/*Add this Line*/
#include "Entity.h"
/*Add this Line*/
 
class Pong
{
        /*Add this Line*/
	Entity player1, player2;
        /*Add this Line*/
};

These will be both the paddles, for the left and the right of the screen.

Now, in our Pong classes InitialiseGeometry method, we need to do just that, Initialise the Entity Instances.

void Pong::InitialiseGeometry()
{
	//As the height of our Paddles, is 80 pixels, we need to determine where the center of the window would be for our paddles.
	//Simple as ((height / 2) - (paddle_height - 2))
	float playerStartY = ((_height / 2) - 40);
 
	//Now Initialise our objects we want to be showing, we set their Width and Height, the their position, fairly simple
       player1.Initialise(15, 80, 20, playerStartY);
 
       //Now we set Player1's color, for this tutorial they both will be white.
       player1.SetColour(1, 1, 1);
 
       //Exactly the same again, except this one is drawn on the right hand side
       player2.Initialise(15, 80, (_width - 35), playerStartY);
       player2.SetColour(1, 1, 1);
}

So we have 2 Paddles now (effectively), both are white, one on the left, one on the right. Both centered vertically. Great! Oh wait, we can’t see them!

Let’s render them!! Can you guess which method we want to render them in? (I’ll give you a hint…Render.)

glClear(GL_COLOR_BUFFER_BIT);
 
//glPushMatrix, will store the current state of the matrix in a special little box, so we can't mess it up. Which gives us a license to do
//what ever we like to it, as we can just pop it back out of the box, and restore it back to the way it was. This is especially useful when
//we are moving objects around space. You may be thinking, we aren't moving them, they are static. Actually, they're not. We are creating
//the boxes at 0,0 (top left in this perspective), then we are moving them to their location.
glPushMatrix();
 
//Call the Entity's render method, which creates a quad, set's it's colour and renders it
player1.Render();
 
//Pop the matrix back to it's previous state, so now any objects we create, will be in the top left, and our first object will be where we left it. 
glPopMatrix();
 
//Same as above, but with Player2.
glPushMatrix();
player2.Render();
glPopMatrix();
 
SDL_GL_SwapBuffers();

Now, compile your game. Run it, just like in the previous tutorials.

make
./Pong

IF compile was a success, you should be presented with a black window and two Paddles. Like this…

pongstep3

If you are, then great! Well done. If not, leave a comment with the problem and i’ll try and see what happened.

As always, here is the entire project source. Also as always, limited comments. Learn from reading the blog, not from taking code ;)

Pong Step 3.zip

Enjoy! Look forward to seeing you again soon. Well, your stat on my web logs anyway!

2 Comments :, , , , , , , more...

Creating the SDL Window

by Dean Thomas on Jan.06, 2009, under Pong Tutorial

Welcome back!

Now, assuming you have follow the first blog post, or already have your system setup ready to compile against SDL and OpenGL, let’s create our First Window!

I am going to keep this code as structured as possible, using classes from the outset, i want this code to be as clean to navigate as possible, so it’s also therefore more expandable and re-usable. At first it seems a pain, but in the long run, it proves it’s worth.

First off, this is a template i use for all my projects now, it’s simple to follow. Download this zip file, and extract it somewhere, this will be where we build our version of Pong. I have already created the Makefile’s and the main.cpp we will use to start with. This is the same zip as the last blog, so it should compile straight out of the box!

Now we have this extracted somewhere, let’s start adding to it! As i said before, i’m trying to keep this as structured as possible, so first off, i’m going to create a class called ‘Pong’, original huh? I will also store these files inside the same as directory as main.cpp (the src folder).

Here are the definitions of the files.

Pong.h

#ifndef PONG_H_
#define PONG_H_
 
#include <iostream>
#include <GL/glew.h>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
 
class Pong
{
private:
        //Width and the Height of the Window
	int _width, _height;
 
        //This is it, THE screen, this is effectively what we will be rendering everything to.
	SDL_Surface *_screen;
 
	bool InitialiseGraphics();
	void InitialiseGeometry();
 
public:
 
	Pong(int width, int height);
 
	bool Initialise();
 
	void Run();
 
	void Uninitialise();
 
};
 
#endif /* PONG_H_ */

Pong.cpp (Part of it…)

#include <cstring>
#include "Pong.h"
 
using namespace std;
 
Pong::Pong(int width, int height)
{
	_width = width;
	_height = height;
}
 
bool Pong::Initialise()
{
	if (!InitialiseGraphics())
		return false;
 
	InitialiseGeometry();
 
	return true;
}
 
void Pong::InitialiseGeometry()
{
 
}

Now, if you save both of those files. So you directory should look like this…

pong-step2-directory

As it is at the moment, that won’t compile. We are still missing a few functions, i missed them out on purpose, so you could understand what they do.

Let’s start with the Pong::InitialiseGraphics method. You will need to place this code into the Pong.cpp file we created earlier.

bool Pong::InitialiseGraphics()
{
	//We only want video, no need for audio/network or even the CD-Rom...
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
		return false;
 
	//We want to double buffer the screen
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
 
	//Create the actual screen for SDL/OpenGL to render to
	_screen = SDL_SetVideoMode(_width, _height, 32, SDL_OPENGL);
 
	std::cout << "SDL Initialised" << std::endl;
 
	glEnable(GL_TEXTURE_2D);
 
	//Set the ViewPort (what we can see) to the same resolution as the actual screen, in this case, 640x480
	glViewport(0, 0, _width, _height);
 
	//Clear the screen again
	glClear(GL_COLOR_BUFFER_BIT);
 
	//Set the Matrix into Projection mode
	glMatrixMode(GL_PROJECTION);
 
	//Load the Projection Matrix
	glLoadIdentity();
 
	//Create an Orthogonal matrix, meaning 2D basically, so we only really work in X and Y
	glOrtho(0, (float) _width, (float) _height, 0, -1.0f, 1.0f);
 
	//Set the Matrix back into Model View mode
	glMatrixMode(GL_MODELVIEW);
 
	//Load the ModelView Matrix
	glLoadIdentity();
 
	//Set the Clear Colour, this is the colour the screen will be cleaered to every time we call glClear(...);
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
	return true;
}

Now, with a quick read through that method, we can see what it’s doing just by reading the comments. This is what will create our SDL window, so that we can render objects to the screen. One current flaw with this method, is that the Bit Depth is locked to 32bit, this could be changed to work the same way as width/height from the constructor. But, you shouldn’t need to worry about that just yet.

Next up, we have the Run method. This is where the good stuff happens, this is the loop for the entire game. Everything that has anything to do with the logic of our game happens in here, if the ball moves, it’s because of this method. This calls the render method on all the objects we want to display, and handles input. So, let’s see it.

void Pong::Run()
{
        //This is a bit we can just use to determine if we want to continue rendering or not
	bool isRunning = true;
        //This is where SDL will provide us with an event, so we can check for KB input, etc
	SDL_Event theEvent;
 
        //Loop forever, until isRunning is false.
	while (isRunning)
	{
                //Poll through as many events as there are available from SDL
		while (SDL_PollEvent(&amp;theEvent))
		{
                        //Check the key that was pressed down...
			switch (theEvent.key.keysym.sym)
			{
			case SDLK_ESCAPE:
                                //If they pushed the ESC key, lets stop the main loop from looping, they want to quit...
				isRunning = false;
				break;
			default:
				break;
			}
		}
 
                //Clear the screen to the colour we defined in the InitialiseGraphics method earlier.
		glClear(GL_COLOR_BUFFER_BIT);
 
	        //This is where everything will get rendered....eventually
 
                //Swap the buffers around, so we can now show one and draw to another, hence Double Buffering
		SDL_GL_SwapBuffers();
	}
}

Thats it for our Run method at the moment, exciting huh? All we do is check for the enter key, and clear the screen. It’ll get a bit more involved soon, i promise ;)

Now, our last method, and one of the important ones. Cleanup! We should let the operating system have it’s resources back, it did give them to use in the first place.

So here it is, as always, well commented for your reading pleasure.

void Pong::Uninitialise()
{
        //Free the Screen surface, basically unload it from memory, we have no need for it now
	SDL_FreeSurface(_screen);
 
        //Tell SDL we are leaving, it should pack up it's bits and come with us.
	SDL_Quit();
}

Now, you have a complete Pong class as a nice little building block for our game, but you have no means of using it at the moment, as main.cpp isn’t at all aware of it, come to think of it, neither is the Makefile.

So, lets update main.cpp, so we can use the Pong class!

Update your Main.cpp to look like this…

#include "Pong.h"
 
int main(int argc, char *argv[])
{
        //Create a new instance of our Pong class
        Pong myPong(640, 480);
 
        //Try an Initialise the SDL and OpenGL APIs
        if (myPong.Initialise())
        {
                //Remember this method? This will block the thread until the game is over.
                myPong.Run();
 
                //Free all those resources we used up.
                myPong.Uninitialise();
        }
}

Now, if you try to compile it, you should get this error.

g++ -O2 -g -Wall -fmessage-length=0   -c -o src/main.o src/main.cpp
g++ -o Pong	 src/main.o -lSDL -lGL -lSDL_ttf
src/main.o: In function `main':
/your_path_here/Pong/src/main.cpp:12: undefined reference to `Pong::Pong(int, int)'

What this means is, it doesn’t know where to find the actual code for that method. Pong(int, int) which is the constructor. Now, we have to make a quick edit to our Makefiles, to point to this object.

Open up the Makefile, in the Pong folder with your favourite text editor, and replace this line

OBJS =          src/main.o

with

OBJS =          src/main.o src/Pong.o

Now open up the Makefile in the ’src’ folder with your favorite text editor, and replace this line

OBJS =          main.o

with

OBJS =          main.o Pong.o

Now, back to our command line, try running ‘make’ now, it should compile fine, with the following output.

g++ -O2 -g -Wall -fmessage-length=0   -c -o src/main.o src/main.cpp
g++ -O2 -g -Wall -fmessage-length=0   -c -o src/Pong.o src/Pong.cpp
g++ -o Pong	 src/main.o src/Pong.o -lSDL -lGL -lSDL_ttf

Now, run the application by typing in

./Pong

And you will have a nice 640, 480 window, with a black background.

Congratulations, you have now created a Window using SDL that supports OpenGL Extensions.

Here is the final product, won’t learn anything just by taking this though!! Most of the comments are missing.

Pong.zip

3 Comments :, , , more...

OpenGL, SDL, C++, Ubuntu

by Dean Thomas on Jan.06, 2009, under Pong Tutorial

Hey ya’ll.

Before i start on my little blog adventure here, i’d first like to say, this probably isn’t the most efficient way, or the best way to achieve a simple game using SDL and OpenGL. My good friend over at TheNewHorizon is a freak for making sure everything is as good as can be possible and most optimised. I am too, but not when i’m learning :) Not that it’s a bad way to learn of course.

First off, the boring bit. Let’s setup our environment so we can compile against SDL and OpenGL, of course using C++.

Now, i use Ubuntu (much to my friend mentioned aboves disgust…) 8.10 Intrepid Ibex as my OS, and have done for a few months now, had no need what-so-ever to boot into windows. It’s great :)

So, this will be mainly aimed at people using Ubuntu, over at TheNewHorizon there is a blog post about setting up Visual Studio Express 2008 for use with SDL and OpenGL.

Let’s begin.

Fire up a console, we need to install packages so we can compile some c++ code. (I am starting a fresh here with a brand new virtual machine, feel free to jump to the relevant step for you…)

Run the following command (will require an internet connection)

sudo apt-get install g++

Once this has completed, we now have a C++ Compiler on your system.

So we can compile the SDL/OpenGL application, right? Not quite yet, we need to install the libraries, and their development headers.

sudo apt-get install libsdl1.2-dev libsdl-ttf2.0-dev libglew1.5-dev;

What was that?

libsdl1.2-dev are the development headers required to compile against SDL v1.2.
libsdl-ttf2.0-dev are the development headers required to use TTF Fonts inside of SDL.
libglew1.5-dev are the development headers required to compile against OpenGL.

Once these are all installed (should run through fine, comment with your issues!) we are able to compile our Pong game. Of course, you’re not able to, but thats in another blog post coming next. This was just to setup your compiler ready for SDL and OpenGL.

So, download the attached zip file, extract it to a folder of your choice, then in your console navigate to the Pong folder. It should look just like this when you run an ‘ls’.

dean@dean-desktop:~/Documents/Eclipse Projects/CPP/Blog/Step 1$ ls
Makefile  src

Now just run this command…

make

And it should spit out a load of output like this…

g++ -O2 -g -Wall -fmessage-length=0   -c -o src/main.o src/main.cpp
g++ -o Pong	 src/main.o -lSDL -lGL -lSDL_ttf

Congratulations, you just compiled your first application that is linked in with SDL, OpenGL and SDL_TTF. Run it by typing in

./Pong

Now, for the IDE. I personally use the Eclipse CC++ IDE, straight from the Eclipse website. It’s around 68mb, excluding the Java Runtime you will need to install. You can use anything that can edit a text file. Vim is very nice, i just prefer the IDE Feel.

In the next blog post, we will be initializing a simple window, and clearing it a specific colour!

1 Comment :, , , , , more...

Object References…

by Dean Thomas on Dec.20, 2008, under .NET

Usually in .NET, any object i instantiate i keep a reference to it until i don’t need it anymore, which is a common thing with any programming language. However, there are times when you don’t need a reference, you just want to call something and not care about the object. Which is what happened.

Basically the scenario is, i had a windows service that runs 24/7 which does data importing every x hours, with a number of data providers setup, all having their own times to import the data. And every 10 minutes, a thread is created to check to see if anything needs to be run, if it does, it runs it, if not then it just sleeps for 10 minutes again.

Now instead of actually calling a Thread.Sleep(10000), i figured it would make sense to use a Timer from the Diagnostics namespace, because i could say, in 10 minutes, call method X. Which was perfect! And it worked a treat. Sometimes.

All through development it was fine, through testing was fine (got very lucky, i guess) and then it went live, for the first few days it was fine (we were updating it quite alot so stopping-starting the serivce). Then it hit the weekend, come back monday morning, nothing. No imports since friday at 9pm. What the…?

Hunted through the code, nothing. It made NO sense that the data wasn’t importing, all the logic was there, i even called the other guys round for an idiot check. No-one could see the problem. So i thought, maybe an exception isn’t bubbling up correctly and we’re not getting it logged… Threw a whole host of extra debug logging in and re-deployed the service…sure enough, same thing happened again.

After about 30 minutes of reading up on the timer class, i realise 2 things.

1) It has a dispose method. Which means i should always have a reference to it, because when i’ve finished with it, i need to dispose of it.
2) MSDN is always the last place i look, but always has the answer. Why don’t i ever look there first?!

As it turns out, because the garbage collector in .NET (and rightly so) comes and clears memory when it wants to, any objects that don’t have a reference, will get nuked. Which is exactly what was happening. We were setting the timer, then sometimes, .NET was coming along and clearing it because we had no reference to it. Therefore preventing the importers from running, and the service of course was still running…but not actually doing anything as the main timer’d thread was killed off.

Now i have a member of the class which has a reference, and i dispose of it when the service stops/restarts.

It’s really weird, i knew .NET did that, but it didn’t even occur thats what could be happening. But, we all learn from our mistakes!

So, Keep a reference to your objects and make sure you dispose of them when your done! Don’t make the mistake i did…

2 Comments more...

PHP, WMI, COM (How many more abbreviations can i get?)

by Dean Thomas on Dec.14, 2008, under PHP

Well, to start with, apologies for the title line… why is everything abbreviated when it comes to computers? I guess it can’t do my SEO work any harm, right?

Anyway, back to something meaningful.

I’ve begun writing a little DNS Manager in PHP, that runs on an IIS 6/7 web server. Initially i was going to write this in .NET as it has alot of support for WMI out of the box, using the ManagementObject classes. But i work in ASP.NET for 40 hours (at least) a week, i like to play with different languages. (IIS 7 + Windows Server 2008 + PHP 5  - http://www.waxer.nl/?p=72)

So, first off, how do we use COM in PHP? Fairly straight forward it would appear.

<?php
      $comObject = new COM ("WbemScripting.SWbemLocator");
?>

Thats it. I now have a COM object loaded up into my variable. It’s nice to see that it’s just as easy if i was using say VBScript to accomplish this task.

So, now i want to connect to the DNS Service, so that i can list all of the zones i currently have setup. Again, a resonably simple task, using my above $comObject i can connect, and iterate through all DNS Zones.

<?php
      /*Connect to the DNS Server, first param is the Host, second is the Namespace, 
        third is the username, fourth is the password (the last two are only required for a remote machine)*/
      $dnsService = $comObject->ConnectServer('localhost', 'rootMicrosoftDNS', '', '');
 
      //Loop through every instance of the class MicrosoftDNS_Zone in our DNS Service.
      foreach ($dnsService->InstancesOf("MicrosoftDNS_Zone") as $existingZone)
      {
          //For now, just echo it's name, just so we can see what Zones we have setup.
          echo 'Zone Name: ' . $existingZone->Name;
      }
?>

And thats, it, this is how we can show all of the zones inside a Microsoft DNS Server.

As you can see, we call an InstancesOf method inside our $dnsService variable, this does exactly what it says on the tin. It returns an array of ALL the specified instances inside this object. Which is great, because we can also call the same method to return all instances of A Records, or SOA Records. Which is very handy for writing a DNS Management portal!

The MicrosoftDNS_Zone is a class, that is provided by the WMI service in WIndows, if you follow the link provided, you can see all of it’s members, these are ALL fields we can view. You will also notice that the MicrosoftDNS_Zone class has a number of methods available to it too.

I will provide another blog on how to create/delete zones in your Microsoft DNS Server!

8 Comments :, , , , , more...

Sun’s VirtualBox Networking (Ubuntu 64Bit Intrepid Ibex)

by Dean Thomas on Dec.14, 2008, under Ubuntu

Recently i started a little PHP Project, where i wanted to manage Microsofts DNS server via a nice little web interface, of course i would have to use COM Object for this.

So, first off, i needed a Windows Server machine… a friend told me that VMWare Server was free to use, so i grabbed it. That turned out to be a dead end, after installation it just hung my PC (Running server 2003 or 2008) so i removed that, and installed Virtual Box. It’s great, simple to use (more like VMWare Workstation, whcih didn’t work either.) and fast, which is just what i was after.

# wget http://download.virtualbox.org/virtualbox/2.0.6/virtualbox-2.0_2.0.6-39765_Ubuntu_intrepid_amd64.deb
# sudo ipkg --install virtualbox-2*.deb

And that was it, VirtualBox installed and ready to run. All seemed too easy. Why wasn’t VMWare this easy?

VirtualBox Main Window

VirtualBox Main Window

As you can see, i’ve taken this screenshot after i’ve got an installed version of 2008 running. All you have to do is click New, follow the few simple steps, mount your CD/DVD and click run. That really is it. Follow the install instructions, and within ~30mins you should have a full Windows 2008 VM Running.

Now i came across a slight issue. The network configuration defaults to NAT Type, which is fine for most. As it uses your PC’s connection for it’s network, so you have an internal IP address. You will be able to connect to the internet (as it’s routed through your PC - The host). But, the internet will not be able to connect to you. I needed to be able to view my IIS Server remotely, from another machine across the globe.

So to do this, the network has to be setup as ‘Host Interface’, which means you can use an interface from the host machine. So, we also need to create a new host on the virtual machine, which will bridge between eth0 (eth0 in my case, could be ethX for you).

This is how your Network pane should look.

VirtualBox Settings

tap0 is the device name we need to create, which can be done by create a simple bash script that creates the new device, sets up the bridge between your ethX and the tap0 and then gets an IP Address for the tap0 device.

#!/bin/bash
#$1 = Username
#$2 = Local Device
#$3 = EthX IP Address
#$4 = Tap0 IP Address
 
sudo tunctl -t tap0 -u $1
sudo chmod 666 /dev/net/tun
sudo /usr/sbin/brctl addbr br0
sudo /sbin/ifconfig eth0 0.0.0.0 promisc
sudo /usr/sbin/brctl addif br0 $2
sudo /sbin/dhclient br0
sudo /usr/sbin/brctl addif br0 tap0
sudo ifconfig tap0 $4 up
sudo bash -c 'echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp'
sudo route add -host $3 dev tap0
sudo arp -Ds $3 $2 pub

Save this as createbridge.sh.

This script requires 4 parameters, your local username (in my case it was dean ;)), the local device you want to bridge (eth0 for me), the IP address of your eth0 device (192.168.1.100 for me) and the IP Address you want the tap0 device to get (i chose 192.168.1.200), i call it like this when i log onto my machine.

# sh createbridge.sh dean eth0 192.168.1.100 192.168.1.200

Wait for it to finish, then you should have a new br0 device which is the bridge which will have the IP Address of your ethX device. You should also have a new device called tap0 which will have the IP Address you specified, mine being 192.168.1.200.

And that is it, i fired up my VM, straight into Windows, instantly viewable from the network and the internet. Perfect!

Hope this helps people that had the same problem.

Leave a Comment :, , , , more...

Music Aggregator!

by Dean Thomas on Mar.08, 2008, under Uncategorized

Hey anyone who actually reads this.

I’m sick of searching for a music video, or trying to find lyrics without getting innundated with my web browser making noises and slowing down because annoying popups want to abuse my machine. So this project (side project, not spending much time on it…) is gunna fix all my issues.

With an AmazonAPI Hooked in, i can search for artists. I’m in the process of writing a Lyrics web scraper and after that is videos (YouTube, etc) so that i can have all the info i need about a band in one place. Google is a wonderful thing, but everything in one place is much more efficient.

Anywho, here is the current url (Removed) it doens’t do much except cache the results, as the AmazonAPI has restrictions on how often i can speak to them (1 hit per second) it’s better i cache the results as it’ll speed up the search and prevent Amazon removing my account.

If anyone could just type in a few random bands, i would be greatful. I just need the content then i can have a bigger website, community driven effectively.

I don’t want to hear about bugs, crashes, slowness, this is so far from being ready it’s not true. But you can never have enough content, hence the release.

I will be writing a simple MP3 Tag Reader that’ll run through my collection of music, populating the DB too, should anyone be interested in devoting some time to running an app through their collection i will be greatful (just leave a comment). Sourcecode will be released with of course to prove i’m not about to chuck a worm onto your machine.

Cheers!

Dean

13 Comments more...

Usenet ReadLine()

by Dean Thomas on Feb.12, 2008, under Uncategorized

Ever tried writing a Usenet client before? Even a simple little one that just downloads an image from your favourite group.

Well, it can be a pain. The spec is simple enough, everything is explained well in the 2 RFCs. But a couple of things weren’t so clear when i started.

First off, the curse of the double dot. For most Usenet calls (Body, Head, etc) its way of notifying you that it has finished sending you data, is to send you a ‘.’. Which is great, nice simple way to let me know that you have finished sending me the information.

However, when you receive a file from usenet, you tend to do it line by line, so you can check for such an end of message. But what if your line of data starts with a ‘.’ because, well it just might. It just adds another ‘.’, so it now becomes ‘..’ which is fine, because i know it’s not the end of the message, and i can just carry on as normal. Do NOT forget to remove one of those ‘.’ otherwise your file will appear as ‘corrupt’ even though it may only be one byte at the end.

Secondly, the encoding. I spent ages trying to figure out why my files were completely different to what they should be, and why my results werent matching up with what say Outlook express could return me. For those of you that didn’t know, Outlook express is a pretty neat Usenet client, terrible as an email client however.

Anywho, usenet files are posted as iso-8859-1, so any file saving that gets done, MUST use that encoding, or again corruption. Imagine not removing a . and saving with the wrong encoding, thats a fun debugging session.

Well, i have attached a sample function that will read a line response from Usenet, and return it as a string (iso-8859-1). It handles the double dot, at the end of the function as you can see.

I Hope this helps someone and saves them more problems than i had…

D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public string ReadLine()
{
    ArrayList returnedBytes = new ArrayList();
    byte[] previousByte = new byte[1];
    byte[] thisByte = new byte[1];
    NetworkStream reader = ServerConnection.GetStream();
 
    while (true)
    {
        //Read a byte, check it
        int received = reader.Read(thisByte, 0, 1);
 
        //Check the byte, let's see what it is...
        if (received == 1)
        {
            bool addByte = false;
            bool endOfLine = false;
 
            //Check if we have a previous byte
            switch ((char)previousByte[0])
            {
                case '\r'://Ignore this byte, it's probably a \n
                    addByte = true;
                    break;
                default:
                    //No previous byte
                    addByte = true;
                    break;
            }
 
            //Check for New Line
            if ((char)thisByte[0] == '\n' &amp;&amp; (char)previousByte[0] == '\r')
            {
                endOfLine = true;
            }
 
            //Set the previous byte
            previousByte[0] = thisByte[0];
 
            //Add this byte?
            if (addByte)
                returnedBytes.Add(thisByte[0]);
 
            //Is this the end of the line?
            if (endOfLine)
                break;
 
        }
        else
        {
            break;
        }
 
    }
 
    Encoding usenetEncoding = Encoding.GetEncoding("iso-8859-1");
    string finalLine = usenetEncoding.GetString((byte[])returnedBytes.ToArray());
 
    if (finalLine.StartsWith(".."))
        finalLine = finalLine.Remove(0, 1);
 
    return finalLine;
}
Leave a Comment :, , , , , , , , more...

Looking for something?

Use the form below to search the site:

Custom Search

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit our friends!

A few highly recommended friends...

Archives

All entries, chronologically...