Read .blend file materials

Compiling, libraries, modules, coding guidelines and porting

Moderators: jesterKing, stiv

Post Reply
jolin1337
Posts: 0
Joined: Tue Sep 24, 2013 9:14 am

Read .blend file materials

Post by jolin1337 » Tue Sep 24, 2013 9:25 am

Hi,
This is my first post on this forum.

My current project is to write a c++ application for reading a .blend file. I have been successful until now. To test my application I render it in OpenGL. I have read the materials from a .blend file that contains one mesh with 6 materials attached to different faces. It works fine except that I can't get the order/index of the materials to match the face property "mat_nr" as I believe it's intended for.

So my questions are:
How to read the correct order of the material **mat property?
Is the mat_nr the correct index of the material attached to that the specific face?

jolin1337
Posts: 0
Joined: Tue Sep 24, 2013 9:14 am

Re: Read .blend file materials

Post by jolin1337 » Thu Sep 26, 2013 5:15 pm

My code is written like this when reading a mesh material list, this is obvious wrong, any one that can point me to the right direction? :?:

Code: Select all

void Mesh::parseMaterials(StructureDNA *sdna, 
				FileBlockHeader *fbh, std::vector<Material > *mat) {
	if(fbh == 0 || totcol == 0) 
		return;
	FileBlockHeader *mfbh = sdna->getFileBlock("**mat", fbh),
					 *next = 0, *prev = 0;

	if(mfbh) {
		printFields(mfbh, sdna);
		next = sdna->getFileBlock("*next", mfbh);
		prev = sdna->getFileBlock("*prev", mfbh);
	}
	int j = 0;

	while(next)  {
		std::string colname = next->getString("id.name", sdna);

		for (unsigned int i = 0; i < mat->size(); i++) {
			if(colname == mat->at(i).name){
				materials.push_back(&(mat->at(i)));
				// printFields(next, sdna);
				j++;
				break;
			}
		}

		next = sdna->getFileBlock("id.*next", next);
	}
	while(prev)  {
		std::string colname = prev->getString("id.name", sdna);

		for (unsigned int i = 0; i < mat->size(); i++) {
			if(colname == mat->at(i).name){
				materials.push_back(&(mat->at(i)));
				// printFields(prev, sdna);
				j++;
				break;
			}
		}

		prev = sdna->getFileBlock("id.*prev", prev);
	}
}

sphaero
Posts: 0
Joined: Tue Feb 28, 2012 3:19 pm

Post by sphaero » Thu Oct 03, 2013 7:42 pm

I'm not sure what code you use but I've read a lot of the data inside a .blend using FBT from GameKit. Check http://www.gamekit.org there's a lot of code there that does the same.

jolin1337
Posts: 0
Joined: Tue Sep 24, 2013 9:14 am

Post by jolin1337 » Sat Oct 05, 2013 6:47 pm

sphaero wrote:I'm not sure what code you use but I've read a lot of the data inside a .blend using FBT from GameKit. Check http://www.gamekit.org there's a lot of code there that does the same.
Nice you are correct, there is a lot of code there, I'll check it out and see if I can find something.
I believe that there is something I don't understand though. It's about the material structure in the .blend file. The code you saw was developed by my self and I feel that I can have read the **mat variable in the wrong way.

My method:
  • 1. First I read an integer from **mat. lets call the integer addr
    2. Then I read the file-block in the position addr, that will give me *mat. This file-block becomes of the type LINK.
    3. I would expect to have more than 2 pointers *next, and *prev to play around with at this point.(one mesh can have more than 2 materials). This is something I think is very confusing.
It's nice to have someone to reflect the ideas one have, so I appreciate every answer you give.
Some Ideas about my problem?

sphaero
Posts: 0
Joined: Tue Feb 28, 2012 3:19 pm

Post by sphaero » Sat Oct 05, 2013 10:40 pm

I think you are correct in that you might be wrong :) However I'm not familiar with the data structure of materials by heart so I can't help you there. I think how AnimKit does could be of help: http://code.google.com/p/gamekit/source ... der.cpp#88

jolin1337
Posts: 0
Joined: Tue Sep 24, 2013 9:14 am

Post by jolin1337 » Sun Oct 06, 2013 2:01 pm

Nice, it is still confusing about the link type of the data structure but I think I have solved it now. I solved it by ignoring the structure type and read past the structure, and I read the data as it only would be integers. With the count of totcol(the amount of materials) and it worked! I know that my code are not documented at all but if anyone would be intrested in my complete solution here you go:

Code: Select all

void Blender::Mesh::parseMaterials(StructureDNA *sdna, 
					FileBlockHeader *fbh, std::vector<Material > *mat) {
	if(fbh == 0 || totcol == 0) 
		return;

	FileBlockHeader *mfbh = sdna->getFileBlock("**mat", fbh);

	if(mfbh) {
		for (int i = 0; i < totcol; i++) {
			int addr = mfbh->getInt(0, i, 4); // offset, position, 
			
			// This is a color fileblock
			FileBlockHeader *color = sdna->getFileBlockByAddress(addr);
			if(color == 0) return; // if no color found abort
			
			// get the name of the material
			std::string colname = color->getString("id.name", sdna); 

			for (unsigned int j = 0; j < mat->size(); j++) { // find the mat in global mats
				if(colname == mat->at(j).name){		// a match
					materials.push_back(&(mat->at(j)));// add the material 
					break;
				}
			}
		}
	}
}
Thanks for the response sphaero :D

Post Reply