Archive

Archive for the ‘Coding’ Category

Beauty of Unity3D

June 15th, 2010 admin No comments

Previously I touched a bit on adding 3D content to a page using the, as yet, unfinalized WebGL standard. The page I made was simple and displayed a non-shaded bspline. But what if you aren’t savvy or maybe you lack the time to wrangle the oddities of OpenGL? The best option that I’ve found so far is Unity3D, a free(for the Indie version) game engine.

One of my most popular posts covers merging Ogre3D w/ Havok physics. That project actually continued long after the page I posted was up (sadly the code couldn’t be updated as it became an official project) and I was having a blast. The problem was I never had enough time. As the only developer on the project I had to handle every piece of the engine. I could pull from many open source options but integration was never fast and easy, like a Yeti. On top of that there wasn’t any sort of scripting framework, all changes had to be written in raw C++ and recompiled. Scripting was always planned but kept taking a back seat to graphics, networking, and physics.


Why am I blathering (BLATHERING BLATHERSKITE!…. Anyone? DuckTales?) on about time and 3D engines? Unity3D pretty much does everything you need and then some w/o the hassle of coding an entire engine. The beauty of their engine isn’t necessarily the tech., it’s the editor. Simple to understand, easy to use, and extremely friendly on novice users. Indeed, everything is tied to an impressive C#/Java scripting framework that makes accessing existing core functionality a snap. Coupled w/ an active community and some decent examples Unity3D is very easy to pick up.

Scripts are compiled on the fly in to a sort of pseudo bytecode(also known as jit compiled, or just in time compiled).

It is around 20 times faster than traditional javascript and around 50% slower than native C++ code.

The only real downside is the lack of control over the core at the C++ level. Adding in features is definitely possible but if you are someone that needs complete control over every aspect of his/her engine you’ll be disappointed. All this means is you have to be clever with the tools you are given in order to create a unique game. Additionally if you are looking to make something other than a generic RTS or FPS you’ll need the pro version which offers full shader support and RTT.

To see an example, click below to download the Unity plugin. After which the 3D image of a toy gun should appear. This is a VERY simple model viewer I threw together in maybe 10 minutes? It took me longer to write this post.


Left/Right Arrow Keys – Rotate around Y-Axis (Spin)
Up/Down Arrow Keys – Rotate around X-Axis (Tilt)

And this is the only script in that scene:

var rotateSpeed : float = 1.0;
var center : Vector3 = Vector3.zero;
var prefab : Transform;
 
 
private var windowRect : Rect = new Rect(0,0,150,50);
 
function Awake(){
	///calculate model center;
	var mesh : Mesh = GetComponent(MeshFilter).mesh;
	var bounds = mesh.bounds;
 
	///Be sure to apply all transformations current present in the model.
	center = mesh.bounds.center;
	center = transform.rotation * center;
	center = center * transform.localScale.x;
	center += transform.position;
 
	///Draw a dummy object to the scene, not necessary but helps to debug odd centers.
	print("Center: " + center.x + "," + center.y + "," + center.z);
	Instantiate(prefab,center, Quaternion.identity);
}
 
function OnGUI () {
	windowRect = GUI.Window (0, windowRect, SpeedGUI, "Speed Control");
}
function SpeedGUI(id : int){
	rotateSpeed = GUI.HorizontalSlider (Rect (25, 25, 100, 30), rotateSpeed, 1.0, 25.0);
}
function Update () {
 
	//Key left/right & up/down key movements
	var rotZ = Input.GetAxis("Vertical");
	var rotY = Input.GetAxis("Horizontal");
 
	//Rotate model around it's center.
	transform.RotateAround(center, Vector3.up,-rotY * rotateSpeed);
	transform.RotateAround(center, Vector3.right,rotZ * rotateSpeed);
}
Categories: Coding, Technology Tags: , , , ,

WinSCP Wrapper (Managed c++)

June 14th, 2010 Jerdak No comments

Here is a little code I wrote to help me access WinSCP via Managed C++.

The code is extremely simple.  A worker thread is spawned which reads from a message packet.  Even though this class uses a worker thread it is technically synchronous.  You can only run a new WinSCP command when the last one has been completed.  The basic logic is thus:  Assign Command to WinSCP -> WinSCP Runs Command Automatically -> WinSCP Returns to a MessageComplete delegate -> Assigned a Command to WinSCP

There isn’t a particular reason for my lack of true asynchronous support other than a lack of time for proper coding.  The time saved by running commands from a queue is negligible given how little I do with the data I request in my apps.  That’s also why you’ll see the beginnings of thread safety (locking) but why it isn’t complete.  Since everything has to run in a specific order there is no need to lock any variables.

The code for this project is being attached directly to this post rather than in my SVN account.

Usage:

ref class ScpRun {
public:
	ScpRun(){
		_commandList = gcnew System::Collections::Generic::List<WinScpCmd^>;
		_scp = gcnew WinScpWrapper();
		_this = this;
		_account = gcnew String("");
	};
	bool Done(){return _bDone;}
	void Run();
	void Stop(){_this->_scp->RequestStop();}
 
	///Get/Set WinSCP account name
	property String ^Account {
		String ^ get(){return _account;}
		void set(System::String ^ s){_account = s;}
	};
protected:
 
	///WinSCP message is complete
	static void ScpMessageComplete(System::Object ^sender, WinScpEventArgs ^args);
private:
 
	///WinSCP wrapper API
	WinScpWrapper ^_scp;
 
	///Command stack (each return message from WinSCP)
	System::Collections::Generic::List<WinScpCmd^> ^_commandList;
 
	///Self-referential pointer for worker thread
	private: static ScpRun ^_this;
 
	///Worker thread complete?
	bool _bDone;
 
        ///WinSCP account name
	System::String ^_account;
};

There isn’t much going on here. We create a generic WinSCP handler class. In my example we create a command stack (just a list), each successive command is sent to WinSCP when the previous one is complete.

ScpRun::Run

void ScpRun::Run(){
	_bDone = false;
	{	///Create command list
 
                //The very first call MUST be to open an account name.  I suggest setting up an easy name using WinSCP that you can reference here.
                _commandList->Add(gcnew WinScpCmd(WSC_OPEN,_account));
 
                //Next we'll add a command to print the current working directory	
		_commandList->Add(gcnew WinScpCmd(WSC_PWD,""));
 
                //Now lets dump the contents of our current directory
		_commandList->Add(gcnew WinScpCmd(WSC_LS,""));
 
                //Lastly be sure to kill your connection
		_commandList->Add(gcnew WinScpCmd(WSC_CLOSE,""));
	}
 
        //Pull the first command off our command stack and call WinSCP
	WinScpCmd ^tmp = _commandList[0];
	_commandList->RemoveAt(0);
 
        //Here we send our command to WinSCP, arguments are parsed by the class
	scp->wsc_call(tmp->Command,tmp->Arguments);
 
        //Be sure to assigned a MessageComplete callback function
	scp->WSCMessageComplete += gcnew WinScpWrapper::MessageComplete(&ScpRun::ScpMessageComplete);
 
        //Tell WinSCPWrapper it's time to start
        scp->RequestStart();
}

Again, all real simple code. We’ve added 4 commands to our command stack and we’ve sent the first off to be run. When that command is complete (successfully or not) it will push out an event to any MessageComplete handlers. I should note here that there isn’t any sort of timeout value. An assumption is made (wrongfully or not) that WinSCP will always return a value.

ScpRun::ScpMessageComplete

void ScpRun::ScpMessageComplete(System::Object ^sender, WinScpEventArgs ^args){
	//Arguments only have 2 states, success or failure.
        if(!args->_bSuccess){
		switch(args->_trigger){
			case WSC_PWD:
			case WSC_LS:
			case WSC_OPEN:
			case WSC_CLOSE:
				printf("Crap-sicle our command has failed.");
				break;
			default:
				break;
		}
		printf("[Command %s failed.]\n",args->_fullCommand);
	} else {
		switch(args->_trigger){
			case WSC_LS:{
				break;
			case WSC_PWD:
				break;
			default:
				printf("Command %s complete.\n",args->_fullCommand);
				printf("   - Value: %s.\n",args->_value);
				break;
		}
	}
 
	///If command list contains more commands, run them.  (Demo only)
	if(_this->_commandList->Count > 0){
		WinScpCmd ^tmp = _this->_commandList[0];
		_this->_commandList->RemoveAt(0);
		_this->scp->wsc_call(tmp->Command,tmp->Arguments);
	} else {
		_this->_bDone = true;
	}
}

Here we handle return messages from our WinSCP wrapper. It would be advisable to add some code here to handle an error from WSC_OPEN that tells the command stack to stop issue commands and set _bDone to true;

The only remaining action is to run our handler class:

	ScpRun ^scp = gcnew ScpRun ();
	scp->Account		= "dummy_account_name";
	scp->Run();
 
	//loop until done
	while(!scp->Done()){
		Threading::Thread::Sleep(15);
	}
	//Tell SCP to stop which in turn tells our WinSCP wrapper to kill its worker thread.
	scp->Stop();

I should mention the WinScpWrapper files. There are some lines that look like the following:

#include <GIniWrapper.h>
//gcnew String(config.getValue.....

You’ll have to remove references to and replace any calls to ‘config.getvalue’ w/ raw values. You’ll see in my get value though that the 3rd argument is actually a default value, just use these. It’s important that you use the same delimiter and cmd_ender that I use. WinSCP, as far as I can tell, doesn’t return any sort of codes. When your command is complete nothing is sent to say as much. You might be able to search for blank lines but I wasn’t sure if these would show up in other commands. Instead what I’ve done is after I issue a command to WinSCP I issue an additional command w/ ‘__END_CMD__’ as the message. WinSCP won’t know how to parse this command but it will still be written to the process handlers output. In this way we can search for valid commands between subsequent ‘winscp>’ command line tags. It’s a kludge but it works.

Categories: Coding Tags: , , , ,

Bezier Patch

December 21st, 2009 admin No comments

bezier
No fanfare, no lengthy preamble, just the code to a bezier patch generator:

// Bezier.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
#include <3DIO/3DIO.h>
#include <vector>
#include <string>
 
using namespace tdio_library;
using namespace std;
 
void create_patch(float step);
void save_patch(const string &name);
void load_bez(const string &name);
 
vector<vector3> pts;
vector3 ctrlPts[4][4];
vector<std::vector<int>> faces;
 
int main(int argc, char* argv[])
{
	load_bez("config.txt");
	if(argc >= 2)create_patch(atof(argv[1]));
	else create_patch(0.2);
 
	save_patch("test.obj");
	return 0;
}
void load_bez(const string &name){
	FILE *stream = fopen(name.c_str(),"r");
	char buffer[256];
	int ct = 0;
	while(!feof(stream)){
		if(fgets(buffer,256,stream)==NULL)break;
 
		float x[4],y[4],z[4];
		char ch;
		if(buffer[0] == 'c'){
			sscanf(buffer,"%c %f %f %f %f %f %f %f %f %f %f %f %f",&ch,&x[0],&y[0],&z[0],&x[1],&y[1],&z[1],&x[2],&y[2],&z[2],&x[3],&y[3],&z[3]);
			ctrlPts[ct][0] = vector3(x[0],y[0],z[0]);
			ctrlPts[ct][1] = vector3(x[1],y[1],z[1]);
			ctrlPts[ct][2] = vector3(x[2],y[2],z[2]);
			ctrlPts[ct][3] = vector3(x[3],y[3],z[3]);
			ct++;
		}
 
		if(ct >= 4)break;
	}
	if(ct != 4){
		printf("  - Warning, read %d control lines.  Should be 4\n",ct);
	}
	fclose(stream);
}
void save_patch(const string &name){
	FILE *stream = fopen(name.c_str(),"w");
	for(int v = 0; v < pts.size(); v++){
		fprintf(stream,"v %f %f %f\n",pts[v].x,pts[v].y,pts[v].z);
	}
	for(int f = 0; f < faces.size(); f++){
		fprintf(stream,"f %d %d %d\n",faces[f][0]+1,faces[f][1]+1,faces[f][2]+1);
	}
	fclose(stream);
 
}
vector3 get_bez_pt(float u, float v){
	double tmp = 0;
	double c[4] = {1,3,3,1};
	vector3 ret(0,0,0);
	for(int i = 0; i < 4; i++){
		for(int j = 0; j < 4; j++){
			tmp = c[i]*c[j] * pow(u,i) * pow(1-u,3-i)*pow(v,j)*pow(1-v,3-j);
			ret.x += ctrlPts[i][j].cell[0] *tmp;
			ret.y += ctrlPts[i][j].cell[1] *tmp;
			ret.z += ctrlPts[i][j].cell[2] *tmp;
		}
	}
	return ret;
}
void create_patch(float step){
	printf("-- Create Patch--\n");
	printf("  - Step: %f\n",step);
 
	for(float x = 0; x < 3; x+=step){
		for(float z = 0; z < 3; z+=step){
			vector3 pt = get_bez_pt(x/3,z/3);
			pts.push_back(pt);
		}
	}
	printf("  - nPts: %d\n",pts.size());
 
	int width = (float)(3.0f/step + 1.0);
	int height = width;
 
	printf("  - Height/Width: %d\n",height);
	int f = 0;
	for(int v = 0; v < pts.size(); v++){
		if(v+width+1 >= pts.size())break;
 
		if((v+1) % (int)width != 0 || v ==0){
			std::vector<int> tmp;
			faces.push_back(tmp);
 
		        faces[f].push_back(v);
			faces[f].push_back(v+1);
			faces[f].push_back(v+width);
			f++;
 
			faces.push_back(tmp);
			faces[f].push_back(v+1);
			faces[f].push_back(v+width+1);	
			faces[f].push_back(v+width);
 
			f++;
		}
	}
	printf("  - %d faces created\n",faces.size());
}

The 3DIO.h file can be found my open source repository. The function ‘create_patch()’ creates a uniform patch of triangles between 0 & 3 in the X and Z axes. Gradients should be chosen to be between this range, I recommend 0.09. Control points are loaded in the function ‘load_bez()’ from a configuration file that looks like so:

#row 0
c 0 5 0 0 0 1 0 0 2 0 0 3

#row 2 of control pts
c 1 0 0 1 10 1 1 -15 2 1 0 3

#row 3 of control pts
c 2 0 0 2 -5 1 2 25 2 2 0 3

#row 4 of control pts
c 0 0 0 3 0 1 3 0 2 3 0 3

Each row controls 4 control points. You can ignore the ‘c’ value and concentrate on the following 16 floating point values. Like so: c x1 y1 z1 x2 y2 z2…… I recommend modifying the Y values first. Messing with X/Z can have weird consequences. Output is saves as a very basic .obj file.

The code, as always, is provided “as is”, with little explanation. I suggest reading up on Bezier patches to get an idea of what the code is doing. I’m happy to answer questions like usual but do your homework.

Categories: Coding Tags: , , ,

Ogre Windows Forms GUI

August 13th, 2009 admin No comments

ogregui

Awhile back I made a post on combining Ogre and Windows Forms. There was some interest both online and off and a request was made for the solution belonging to said project.

The solution can be found here. And as usual the instructions for accessing my SVN can be found here.

At the time of the initial writing my example was sparse. It launched an empty Ogre scene and we were done. My new example expands just a bit on the Ogre/Windows FORM GUI idea. The biggest addition is the ability to create new plugins. But let’s call a spade a spade, the additional “framework” is nothing more than a simple parameter structure and the a plugin base class specifier.

Additionally (for those who’ve never used Ogre3D) everything inside the Ogre3D engine can be access by Singletons. In other words if I create a mesh in my main program I know I’ll be able to snag it in a plugin as long as I know the exact name.

The basic idea is this. You have a set of unmanaged classes, an ogre frame listener and an ogre app. These handle the core of updating and manipulating Ogre. Around those classes is a managed OgreWrapper. This class is the interface between Windows Forms and the Ogre classes. It handles mouse/keyboard input, updating, and resizing. You also have a plugin manager that handles loading .dll’s and determining if they are valid.

Lord it’s fucking late, I’ll write up a proper tutorial this weekend. Until then please enjoy the free code and if you have questions let me know.

Oh and this was built against Ogre 1.6.3.

How to open an old school Win32 console in a Windows App:

void createConsole(){
	AllocConsole();
	SetConsoleTitle(_T("Fuck message boxes"));
 
	int hConHandle;
	long lStdHandle;
	FILE *fp;
 
	// redirect unbuffered STDOUT to the console
	lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen( hConHandle, "w" );
	*stdout = *fp;
	setvbuf( stdout, NULL, _IONBF, 0 );
 
	// redirect unbuffered STDIN to the console
	lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen( hConHandle, "r" );
	*stdin = *fp;
	setvbuf( stdin, NULL, _IONBF, 0 );
 
	// redirect unbuffered STDERR to the console
	lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen( hConHandle, "w" );
	*stderr = *fp;
	setvbuf( stderr, NULL, _IONBF, 0 );
}
Categories: Coding Tags:

Dynamically Load .dlls

April 23rd, 2009 admin No comments

Another quick code snippet for dynamically loading .dlls using managed c++. Every .dll we load is assumed to have a class called ncgBaseClass. ncgBaseClass contains 2 functions called every time, AttachParams and InitPlugin.

Our first call is AttachParams:

MethodInfo ^mi = p->_type->GetMethod("AttachParams");			//Find the attachparams method
		p->_instance = Activator::CreateInstance(p->_type);				//Create an instance of our assembly type and store it in the plugin list

We get the AttachParams method, create our instance, and are now ready to pass data to the method.

Create plugin parameters and pass them to the .dll:

	ncgPluginParams params;
	params.mainPanel = _mainPanel;
	params.mainMenu = _mainMenu;
	params.dbgConsole = nullptr;
	params.scene = sceneMgr;
	params.sSceneName = gcnew System::String("ExampleSMInstance");
	array<ncgPluginParams ^> ^ar = gcnew array<ncgPluginParams^>(1);
	ar[0] = %params;
	mi->Invoke(p->_instance,ar);

As you can see from the code above I have a plugin parameter class. This class is compiled in to its own library. Each plugin and the program running the plugin loader compile against this library. The example above shows me passing a single item to my plugin. The parameter class contains a pointer to a panel, a menu, a debugging console, and an ogre scene manager. The .dll will do with this as it will.

It’s actually pretty simple once you start playing around. The full code below also contains examples of how to pass KeyUp and KeyDown events to the .dll.

Code:
ncgpluginmanager.h

ncgpluginmanager.cpp

Categories: Coding Tags: