Archive

Archive for April, 2009

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:

Ogre: Manually load .obj

April 23rd, 2009 admin No comments

Thought I’d post a bit more code. The following snippet shows you how to manually load data in to a temporary Ogre resource. Keep in mind that this method does not use a resource manager and, as such, lacks the ability to reuse loaded meshes.

Loading the data from an .obj file.

bool mesh::LoadObj(gcroot<System::String ^> fileName){
	Ogre::String name,shortName;
	char buffer[256];
 
	//Convert System::String to Ogre::String.  
	{
		System::IntPtr ip = System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(fileName);
		const char *str = static_cast<const char*>(ip.ToPointer());
		name = str;
		System::Runtime::InteropServices::Marshal::FreeHGlobal(ip);
	}
 
	//Get shortname for entity creation 
	{
		int idx = name.find_last_of("\\");
		sprintf(buffer,"%s",name.c_str());
		shortName = name.substr(idx+1,name.size());
 
	}
	System::IO::FileInfo ^file = gcnew System::IO::FileInfo(fileName);
	System::IO::StreamReader ^read = gcnew System::IO::StreamReader(file->Open(System::IO::FileMode::Open,System::IO::FileAccess::Read));
	System::String ^line;
	array<System::Char> ^delims = {' ',','};
 
        //Vertex list
	System::Collections::Generic::List<System::Collections::Generic::List<float>^> ^vList = gcnew System::Collections::Generic::List<System::Collections::Generic::List<float>^>;
        //Face list      System::Collections::Generic::Dictionary<System::String^,System::Collections::Generic::List<face_group^>^> ^fList = gcnew System::Collections::Generic::Dictionary<System::String^,System::Collections::Generic::List<face_group^>^>;
	System::String ^group = gcnew System::String("999999");
	int group_id = -1;
 
	fList->Add("999999",gcnew System::Collections::Generic::List<face_group^>);
 
	int nFace=0, nVtx=0;
 
	//Read obj
	{
		while((line = read->ReadLine()) != nullptr){
			array<System::String^> ^tokens = line->Split(delims);
 
			if(line->Length > 0){
				if(line[0] == 'v'){
					try {
						System::Collections::Generic::List<float>^ tmp = gcnew System::Collections::Generic::List<float>;
						tmp->Add(System::Convert::ToDouble(tokens[1]));
						tmp->Add(System::Convert::ToDouble(tokens[2]));
						tmp->Add(System::Convert::ToDouble(tokens[3]));
 
						vList->Add(tmp);
						nVtx++;
					} catch(...){}
				} else if(line[0] == 'f'){
					face_group ^tmp = gcnew face_group;
					tmp->uid = group;
					tmp->group_id = group_id;
 
					tmp->idxList->Add(System::Convert::ToInt32(tokens[1]));
					tmp->idxList->Add(System::Convert::ToInt32(tokens[2]));
					tmp->idxList->Add(System::Convert::ToInt32(tokens[3]));
 
 
					fList[group]->Add(tmp);
					nFace++;
				} else if(line[0] == '#'){
					//Found new group
					if(tokens[1][0] == 'g'){
						if(!fList->ContainsKey(tokens[3])){
							fList->Add(tokens[3],gcnew System::Collections::Generic::List<face_group^>);
						}
						group = tokens[3];
						group_id = System::Convert::ToInt32(tokens[2]);
					}
				}
			}
		}
		read->Close();
	}//end read obj
 
	tdio_library::point3D_t *vtx = new tdio_library::point3D_t[nVtx];
	tdio_library::Face *face = new tdio_library::Face[nFace];
	_perFaceColor = new ncgColorNode[nFace];
 
	int i = 0;
	int k;
	//printf("Filling vertex array...");
 
	//Fill vertex array and get centroid
	for each(System::Collections::Generic::List<float>^ list in vList){
		k=0;
		for each(float val in list){
			vtx[i].cell[k] = val;
			k++;
		}
		i++;
	}
 
	//printf("Complete.\n");
 
	//printf("Filling Face array...");
	i=0;
	try {
		for each(System::Collections::Generic::KeyValuePair<System::String^,System::Collections::Generic::List<face_group^>^> ^kvp in fList){
 
			for each (face_group ^f in kvp->Value){
//				System::Drawing::Color ^color = Painter::HexColor::FromHex(f->uid);
 
				k=0;
				face[i].verts = new int[3];
				face[i].nverts = 3;
				face[i].intensity = -1;
 
                                //obj files lack color so set default to gray.
				_perFaceColor[i].color.r = 150;
				_perFaceColor[i].color.g = 150;
				_perFaceColor[i].color.b = 150;
 
				for each (int val in f->idxList){
					face[i].verts[k] = val;
					k++;
				}
				i++;
			}
		}
	} catch (System::Exception ^ex){
		//printf("Error: %s\n",ex->Message);
	}
	return BuildOgreMesh(shortName.c_str());
}

Building the Ogre mesh:

bool ncgMesh::BuildOgreMesh(const char *meshName){
	Ogre::String name = meshName;
	tdio_library::point3D_t *vtx = _ply->GetVertices();
	tdio_library::Face *face = _ply->GetFaces();
	int nVtx = _ply->GetNumVertices();
	int nFace = _ply->GetNumFaces();
 
	map<int,Vector3> mNormals = GetNormals(vtx,nVtx,face,nFace);
	MeshPtr mesh = MeshManager::getSingleton().createManual(name + "_manual_mesh","Custom");
	SubMesh *submesh = mesh->createSubMesh(name + "_manual_sub");
 
	//Create OgreMesh
	try
	{
		//printf("Building manual OGRE mesh\n");
 
		submesh->useSharedVertices = false;
		submesh->vertexData = new VertexData();
		submesh->vertexData->vertexStart = 0;
		submesh->vertexData->vertexCount = nVtx + 1;
		VertexDeclaration * dec = submesh->vertexData->vertexDeclaration;
		static const unsigned short source = 0;
		static const unsigned short csource = 1;
		size_t offset = 0;
 
		offset += dec->addElement(source,offset,VET_FLOAT3,VES_POSITION).getSize();
		offset += dec->addElement(source,offset,VET_FLOAT3,VES_NORMAL).getSize();
 
		//printf("  - Assigning Vertex Buffer: ");
		HardwareVertexBufferSharedPtr vbuffer = HardwareBufferManager::getSingleton().createVertexBuffer(dec->getVertexSize(source),\
																										 submesh->vertexData->vertexCount,\
																										 HardwareBuffer::HBU_STATIC_WRITE_ONLY);
 
		//printf("1...");
		float *vdata = static_cast<float*>(vbuffer->lock(HardwareBuffer::HBL_DISCARD));
		AxisAlignedBox aabox;
 
		map<int,Vector3>::const_iterator mIter;
 
		_min = _max = Vector3(vtx[0].x,vtx[0].y,vtx[0].z);
		_centroid = Vector3::ZERO;
 
		//printf("2...");
		for(int i = 0; i < nVtx; i++){
			Vector3 pos(vtx[i].x,vtx[i].y,vtx[i].z);
 
			if(_max.x < vtx[i].x)_max.x = vtx[i].x;
			if(_min.x > vtx[i].x)_min.x = vtx[i].x;
 
			if(_max.y < vtx[i].y)_max.y = vtx[i].y;
			if(_min.y > vtx[i].y)_min.y = vtx[i].y;	
 
			if(_max.z < vtx[i].z)_max.z = vtx[i].z;
			if(_min.z > vtx[i].z)_min.z = vtx[i].z;
 
			_centroid+=pos;
		}
		_centroid /= nVtx;
		//printf("3....");
 
		tdio_library::FaceMapNode *faceMap = _ply->GetFaceMap();
 
		for(int i = 0; i < nVtx; i++){
			Vector3 pos(vtx[i].x,vtx[i].y,vtx[i].z);
 
			*vdata++ = pos.x;
			*vdata++ = pos.y;
			*vdata++ = pos.z;
 
			Vector3 normal = Vector3::ZERO;
			int *ind = faceMap[i].ind;
			int nInd = faceMap[i].n_ind;
			int ct = 0;
			for(int k = 0; k < nInd; k++){
				for(int j = 0; j < 3; j++){
					if(_ply->GetFaces()[ind[k]].verts[j] != i){
						mIter = mNormals.find(_ply->GetFaces()[ind[k]].verts[j]);
						if(mIter != mNormals.end()){
							normal += mNormals[_ply->GetFaces()[ind[k]].verts[j]];
							ct++;
						} else {
							normal += Vector3(1,0,0);
							ct++;
						}
					}
				}
			}
			normal/=ct;
 
 
			*vdata++ = normal.x;
			*vdata++ = normal.y;
			*vdata++ = normal.z;
			aabox.merge(pos);
		}
 
		vbuffer->unlock();
 
		//printf("Complete.\n");
 
		//printf("  - Assigning Face buffer");
		submesh->vertexData->vertexBufferBinding->setBinding(source,vbuffer);
		submesh->indexData->indexStart = 0;
		submesh->indexData->indexCount = nFace * 3;
		submesh->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_32BIT,submesh->indexData->indexCount,HardwareBuffer::HBU_STATIC_WRITE_ONLY);
 
		//printf("1...");
		uint32 *idata = static_cast<uint32*>(submesh->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
 
		for(int i = 0; i < nFace; i++){
			*idata++ = face[i].verts[0];
			*idata++ = face[i].verts[1];
			*idata++ = face[i].verts[2];
		}
 
		submesh->indexData->indexBuffer->unlock();
		//printf("Complete.\n");
 
		if(_perFaceColor != NULL){
			//printf("  - Assigning Color buffer");
			offset = 0;
			offset += dec->addElement(csource,offset,VET_COLOUR,VES_DIFFUSE).getSize();
			vbuffer = HardwareBufferManager::getSingleton().createVertexBuffer(offset,\
																			   submesh->vertexData->vertexCount,\
																			   HardwareBuffer::HBU_STATIC_WRITE_ONLY);
			//printf("1...");
 
			RenderSystem *rs = Root::getSingleton().getRenderSystem();
			RGBA *cdata = static_cast<RGBA*>(vbuffer->lock(HardwareBuffer::HBL_DISCARD));
			for(int i = 0; i < nFace; i++){
				int *idx = face[i].verts;
				rs->convertColourValue(ColourValue(_perFaceColor[i].color.r/255.0,_perFaceColor[i].color.g/255.0,_perFaceColor[i].color.b/255.0),(cdata+idx[0]));
				rs->convertColourValue(ColourValue(_perFaceColor[i].color.r/255.0,_perFaceColor[i].color.g/255.0,_perFaceColor[i].color.b/255.0),(cdata+idx[1]));
				rs->convertColourValue(ColourValue(_perFaceColor[i].color.r/255.0,_perFaceColor[i].color.g/255.0,_perFaceColor[i].color.b/255.0),(cdata+idx[2]));
			}
			vbuffer->unlock();
			submesh->vertexData->vertexBufferBinding->setBinding(csource,vbuffer);
			//printf("Complete.\n");
			Ogre::LogManager::getSingleton().logMessage("  - Color buffer loaded");
		} else {
			Ogre::LogManager::getSingleton().logMessage("  - No color buffer to load");
		}
 
		//printf("  - Create mesh boundaries...");
		mesh->_setBounds(aabox);
		mesh->_setBoundingSphereRadius( (aabox.getMaximum()-aabox.getMinimum()).length() / 2.0);
		//printf("Complete.\n");
 
                //Create a customcolour in your own material scripts.  Mine sets ambient and diffuse
                //colors to use whatever was entered manually.
		submesh->setMaterialName("CustomColour");
		//printf("  - Loading finalized mesh...");
		mesh->load();
		//printf("Complete.\n");
 
		//printf("  - Attaching completed mesh to node...");
		Entity *ent = NULL;
		Ogre::SceneManager *_sceneMgr = Ogre::Root::getSingleton ().getSceneManager ("ExampleSMInstance"); 
		try {
			ent = _sceneMgr->getEntity(name + "_manual_ent");
		} catch (...) {
			ent = _sceneMgr->createEntity(name + "_manual_ent",name + "_manual_mesh");
		}
 
		try {
			ent->setCastShadows(false);
			_viewNode->attachObject(ent);
		} catch (Ogre::Exception &ex) {
			//printf("Error[%s at %d]: %s\n",__FILE__,__LINE__,ex.getDescription().c_str());
		}
		_sId = name;
		_bEmpty = false;
		//printf("Complete.\n");
 
		//printf("Reticulating splines.... Complete!\n"); // :) 
	}catch (Ogre::Exception& e){
		//printf("Problem creating ogre mesh: %s\n",e.getDescription().c_str());
		return false;	
	}
	return true;
}

Ogre Custom Color Script (CustomColour.material):

material CustomColour
{
          technique
          {
                    pass
                    {
                         ambient vertexcolour
                         diffuse vertexcolour
                         cull_hardware none
                         shading phong
                     }
           }
}

Excuse my code blocks, the script I use to bound them in to a smaller viewing area is borked atm. I’ll fix it when I get a free minute.

There are a couple of custom data types in there like point3D_t and face. Point3D contains 3 floats: x,y,z. Face contains an array of indices, in this case we assume only 3 as we area loading triangles. There are plenty of libraries out there for handling this type of data, the main focus of my post was the BuildOgreMesh function.

I’ve included an example that also loads color on a per-face basis. In order to make use of this color I had to create a CustomColour material script for ogre. My basic .obj loader doesn’t handle color from a material file, I’ll leave that to the reader. My loader assigns a generic gray color to all the faces.

Categories: Coding Tags:

Amusing Spam and the Users who hate them

April 21st, 2009 admin No comments

I want to share a recent spam comment caught by my filter:

Hi Man!, please, need your help.
Where to buy Tequila Rose in Singapore?

Thenks. I am vaiting for answer!!!

I hate spam, passionately. But what I really hate is the lack of spam tool sophistication. If I have to spend my time cleaning this crap up the least they could do is spell check. Maybe construct proper English sentences. Unless the point is to sound helpless and foreign hoping I’m softhearted enough to render aid. Not that it matters, as I rule I don’t click on links or emails that look like they need to buy a vowel.

dftghrnmj@nrsitw.com is not likely to find his/her Tequila in Singapore. Perhaps they should learn how to do a proper Google search as their key words clearly aren’t leading them in the right direction. I can’t conceive of a scenario in which my page comes up as the result of “Where can I find Tequila in Singapore.”

Give this post a day or 2 to be crawled by Google though and I’m guessing I will now be the number one location of the internet’s tequila finding needs. :)

Categories: Uncategorized Tags:

Asian Surnames

April 14th, 2009 admin No comments

Living in a very liberal state and having been raised by an open minded hippy I sometimes forget we still live in a bigoted world. This is probably old news by this point but a recent texan lawmaker asked of Asians if it would “behoove” them to change their names to something easier to handle.

I especially like that she directs her comments to the Chinese in particular. Because god knows I have a hard time pronouncing such strenuous names as “Ko” and “Li”. In a spectacular back pedal, and in true political fashion, we’re told the comments were not racially motivated and that they were not taken as they were supposed to be. I’m not sure how else you would take what she said. My favorite part to Brown’s excuse is that she had been going to 10 hours straight and it just slipped out. I mean who hasn’t been there right? You’re up late, writing papers, and suddenly you decide to insult non-Caucasian ethnicities. I’ve seen it a thousand times.

Those must have been some hellish 10 hours, what with all the hard work politicians do. Maybe Texas should hire someone who can handle working what most of us consider a normal day.

Categories: Uncategorized Tags:

Antiquated Protocol

April 3rd, 2009 admin No comments

I guess we live in a world where touching the queen of England is more important, news wise, than the war in Iraq and a recession. I’m not British so perhaps I just don’t “get it” but I have no understanding as to why any modern democratic society would continue to maintain the illusion of “royalty.” And let’s be clear folks, the queen of England and her inbred family are nothing more than figure heads to be trotted out at photo-ops.

It worries me that there are still people in this country that don’t understand that the queen and her chromosomaly challenged ilk are nothing more than visual aids. And it bothers me that anyone in a developed nation would capitulate to the whims of these people. How many gaffs (the prince dressing as a Nazi) and snafus are the British willing to cover up for this brood of powerless puppets?

Yikes… that was quite a digression. The reason for my little post was to point out the silliness of the hubbub regarding Michelle Obama touching the queen on her shoulder. I get that back in the day, you know… when royalty mattered, protocol was important to maintain the safety of the royal person. That makes sense to me in the context of the 14th century. But hey, it’s 2009. We don’t have the plague and royalty has no real power. At best the royal family are like celebrities and last I checked people weren’t gasping at someone clapping Brad Pitt on the shoulder.

I truly believe pomp and circumstance have to be earned in some way and not because tradition dictates.

“Listen. Strange women lying in ponds distributing swords is no basis for a system of government. Supreme executive power derives from a mandate from the masses, not from some farcical aquatic ceremony”

Categories: Uncategorized Tags: