Open/Extract Model and Textures from WMB

Posted By: MooseMannequin

Open/Extract Model and Textures from WMB - 12/29/20 20:16

Hello everyone, sorry if this is not the right thread, but I didn't found the right one, so
I'm not familiar with 3GS at all, and need your help.
I have the WMB files from the game and I figured out, it carry model and texture files inside. I need to extract them somehow to edit in the zbrush/maya then, but I don't know how.
I installed Gamestudio A8, but it can't open these files in any of editors. And I found out, one guy did it with Unity and some script, but it's just another one universe for me as well. I can send you the link, if you interested.
I am doing it just for fun and out of curiosity, and need your help so much, thank you gamers.
p.s. Sry if there is mistakes, am not english at all.
Posted By: Dooley

Re: Open/Extract Model and Textures from WMB - 12/29/20 20:49

In the WED program, which unfortunately does not come with the free version of 3DGS, you can extract textures from a .wad file.
Posted By: 3run

Re: Open/Extract Model and Textures from WMB - 12/30/20 09:23

@Dooley as far as I remember, all game studio editors are working in free version (WED, MED, SED, but not sure about the GED). I remember there was a Lite-C version back in A7 times and it didn't have WED support, but it's not available anymore. Aside from that version differences are more about scene management, shader support, etc. Also it seems that the thread creator doesn't want to extract WAD files, but want to somehow extract textures/models from already compiled .WMB file. Sadly, I don't know how to do that.
Posted By: txesmi

Re: Open/Extract Model and Textures from WMB - 12/30/20 13:07

There is some information into http://www.conitec.net/beta/prog_mdlhmp.htm

I did some tests some time ago. It is not really hard.

Code
#include <acknex.h>

#define PRAGMA_PATH "models"

// ------------------------------------------------------------

STRING *strT = "";

TEXT *txtGlobal = {
	pos_x = 10;
	pos_y = 10;
	string = ("GLOBAL", "--------------------");
	flags = SHOW;
}

TEXT *txtObjects = {
	pos_x = 200;
	pos_y = 10;
	string = ("OBJECTS", "--------------------");
	flags = SHOW;
}

TEXT *txtMaterials = {
	pos_x = 400;
	pos_y = 10;
	string = ("MATERIALS", "--------------------");
	flags = SHOW;
}

TEXT *txtTextures = {
	pos_x = 600;
	pos_y = 10;
	string = ("TEXTURES", "--------------------");
	flags = SHOW;
}

TEXT *txtLightmaps = {
	pos_x = 800;
	pos_y = 10;
	string = ("LIGHTMAPS", "--------------------");
	flags = SHOW;
}

TEXT *txtBlocks = {
	pos_x = 1000;
	pos_y = 10;
	string = ("BLOCKS", "--------------------");
	flags = SHOW;
}

TEXT *txtPaths = {
	pos_x = 1200;
	pos_y = 10;
	string = ("PATHS", "--------------------");
//	flags = SHOW;
}

// ------------------------------------------------------------

typedef struct LIST {
	long offset; // offset of the list from the start of the WMB file, in bytes
	long length; // length of the list, in bytes
} LIST;

typedef struct WMB_HEADER {  
	char version[4];        // "WMB7"  
	LIST palettes;          // WMB1..6 only
	LIST legacy1;           // WMB1..6 only
	LIST textures;          // textures list  
	LIST legacy2;           // WMB1..6 only
	LIST pvs;               // BSP only 
	LIST bsp_nodes;         // BSP only 
	LIST materials;         // material names
	LIST legacy3;           // WMB1..6 only
	LIST legacy4;           // WMB1..6 only
	LIST aabb_hulls;        // WMB1..6 only
	LIST bsp_leafs;         // BSP only 
	LIST bsp_blocks;        // BSP only 
	LIST legacy5;           // WMB1..6 only
	LIST legacy6;           // WMB1..6 only
	LIST legacy7;           // WMB1..6 only
	LIST objects;           // entities, paths, sounds, etc.
	LIST lightmaps;         // lightmaps for blocks
	LIST blocks;            // block meshes
	LIST legacy8;           // WMB1..6 only
	LIST lightmaps_terrain; // lightmaps for terrains
} WMB_HEADER;

typedef struct TEXTURE {  
	char name[16];          // texture name, max. 16 characters  
	long width,height;      // texture size  
	long type;	            // texture type: 5 = 8888 RGBA; 4 = 888 RGB; 2 = 565 RGB; 6 = DDS; +8 = mipmaps
	long legacy[3];         // always 0
} TEXTURE;

typedef struct MATERIAL_INFO {  
	char legacy[44];        // always 0 
	char material[20];      // material name from the script, max. 20 characters
} MATERIAL_INFO;

typedef struct LIGHTMAP_TERRAIN {
	long object;            // terrain entity index into the objects list
	long width,height;      // lightmap size
} LIGHTMAP_TERRAIN;

typedef struct BLOCK {  
	float fMins[3];         // bounding box  
	float fMaxs[3];         // bounding box  
	long  lContent;         // always 0  
	long  lNumVerts;        // number of VERTEX structs that follow  
	long  lNumTris;         // number of TRIANGLE structs that follow	
	long  lNumSkins;        // number of SKIN structs that follow
} BLOCK;

typedef struct VERTEX {  
	float x,y,z;            // position  
	float tu,tv;            // texture coordinates  
	float su,sv;            // lightmap coordinates
} VERTEX;

typedef struct TRIANGLE {   
	short v1,v2,v3;         // indices into the VERTEX array  
	short skin;             // index into the SKIN array  
	long  unused;           // always 0 
} TRIANGLE;

typedef struct SKIN {  
	short texture;          // index into the textures list  
	short lightmap;         // index into the lightmaps list  
	long  material;         // index into the MATERIAL_INFO array  
	float ambient,albedo;  
	long  flags;            // bit 1 = flat (no lightmap), bit 2 = sky, bit 14 = smooth  
} SKIN;

typedef struct WMB_INFO {  
	long  type;             // 5 = INFO  
	float origin[3];        // not used  
	float azimuth;          // sun azimuth  
	float elevation;        // sun elevation  
	long  flags;            // always 127 (0x7F)  
	float version;	         // compiler version  
	byte  gamma;            // light level at black  
	byte  LMapSize;         // 0,1,2 for lightmap sizes 256x256, 512x512, or 1024x1024  
	byte  unused[2];  
	DWORD dwSunColor,dwAmbientColor; // color double word, ARGB   
	DWORD dwFogColor[4];
} WMB_INFO;

typedef struct WMB_POSITION {  
	long  type;             // 1 = POSITION  
	float origin[3];   
	float angle[3];   
	long  unused[2];  
	char  name[20];
} WMB_POSITION;

typedef struct WMB_LIGHT {  
	long  type;             // 2 = LIGHT  
	float origin[3];   
	float red,green,blue;   // color in percent, 0..100  
	float range;  
	long  flags;            // 0 = static, 2 = dynamic
} WMB_LIGHT;

typedef struct WMB_SOUND {  
	long  type;             // 4 = Sound  
	float origin[3];   
	float volume;
	float unused[2];  
	long  range;  
	long  flags;            // always 0  
	char  filename[33];
} WMB_SOUND;

typedef struct WMB_PATH {  
	long  type;	            // 6 = PATH  
	char  name[20];         // Path name  
	float fNumPoints;       // number of nodes  
	long  unused[3];        // always 0  
	long  num_edges;
} WMB_PATH;

typedef struct WMB_ENTITY {  
	long  type;             // 7 = ENTITY  
	float origin[3];  
	float angle[3];  
	float scale[3];  
	char  name[33];  
	char  filename[33];  
	char  behavior[33];  
	float skill[20];  
	long  flags;  
	float ambient;  
	float albedo;  
	long  path;             // attached path index, starting with 1, or 0 for no path
	long  entity2;          // attached entity index, starting with 1, or 0 for no attached entity  
	char  material[33];	  
	char  string1[33];  
	char  string2[33];  
	char  unused[33];
} WMB_ENTITY;

typedef struct WMB_OLD_ENTITY {  
	long  type;             // 3 = OLD ENTITY  
	float origin[3];  
	float angle[3];  
	float scale[3];  
	char  name[20];  
	char  filename[13];  
	char  behavior[20];  
	float skill[8];  
	long  flags;  
	float ambient;
} WMB_OLD_ENTITY;

typedef struct PATH_EDGE {  
	float fNode1,fNode2;    // node numbers of the edge, starting with 1
	float fLength;  
	float fBezier;  
	float fWeight;  
	float fSkill;
} PATH_EDGE;

typedef struct BSP_NODE {  
	long   legacy1[2];      // WMB1..6 only  
	short  mins[3];         // bounding box, packed shorts  
	short  maxs[3];  
	long   legacy2;         // WMB1..6 only  
	long   children[2];     // node index when >= 0, -(leaf index + 1) when < 0  
	long   legacy3[2];      // WMB1..6 only
} BSP_NODE;

typedef struct BSP_LEAF {  
	long   flags;           // content flags  
	long   pvs;             // PVS offset or -1  
	short  mins[3];         // bounding box, packed shorts  
	short  maxs[3];  
	long   legacy1[2];      // WMB1..6 only  
	long   nbspblock;       // offset into the bsp_blocks list  
	long   numblocks;       // number of bsp_blocks for this leaf
} BSP_LEAF;

typedef struct BSP_BLOCK {
  long   nblock;           // index of block in the blocks list
} BSP_BLOCK;

// ------------------------------------------------------------

var texFormats[8] = {0, 0, 565, 0, 888, 8888, 0, 0};

typedef struct TX_TEXTURE {
	TEXTURE *texture;
	char name[16];
	BYTE *buffer;
	long bufSize;
	BMAP *bmap;
	long format;
	long mipmaps;
	long width;
	long height;
	
	PANEL *panel;
} TX_TEXTURE;

typedef struct TX_LIGHTMAP {
 	BYTE *buffer;
 	BMAP *bmap;
	
	PANEL *panel;
} TX_LIGHTMAP;

typedef struct TX_TERRAIN_LIGHTMAP {
 	LIGHTMAP_TERRAIN *lightmap_terrain;
 	BYTE *buffer;
 	BMAP *bmap;
	
	PANEL *panel;
} TX_TERRAIN_LIGHTMAP;

typedef struct TX_OBJECT {
	BYTE *buffer;
	long type;
} TX_OBJECT;

typedef struct TX_BLOCK {
	BLOCK *block;
	VERTEX *vertex;
	TRIANGLE *tris;
	SKIN *skins;
} TX_BLOCK;

typedef struct TX_FILE {
	BYTE *buffer;
	long bufSize;
	char version[5];
	
	//objects
	long objCount;
	TX_OBJECT *objects;
	TX_OBJECT *info;
	
	//blocks
	long blkCount;
	TX_BLOCK *blocks;
	
	//materials
	long mtlCount;
	MATERIAL_INFO *materials;
	
	//textures
	long texCount;
	TX_TEXTURE *textures;
	
	//lightmaps
	long lmCount;
	TX_LIGHTMAP *lightmaps;
	
	//terrain lightmaps
	long tlmCount;
	TX_LIGHTMAP *terrain_lightmaps;
	
} TX_FILE;

// ------------------------------------------------------------

void load_textures (TX_FILE *_txFile) {
	WMB_HEADER *_header = _txFile->buffer;
	
	long *_texOffArray = (long*)(_txFile->buffer + _header->textures.offset);
	_txFile->texCount = *_texOffArray;
	str_printf(strT, "Texture count: %d", _txFile->texCount);
	txt_addstring(txtGlobal, strT);
	txt_addstring(txtGlobal, " ");
	
	_txFile->textures = sys_malloc(sizeof(TX_TEXTURE) * _txFile->texCount);
	
	TX_TEXTURE *_txTex = _txFile->textures;
	long *_texOff = _texOffArray + 1;
	long _index = 0;
	for(; _index < _txFile->texCount; _index += 1, _texOff += 1, _txTex += 1) {
		_txTex->texture = (TEXTURE*)(((BYTE*)_texOffArray) + *_texOff);
		memcpy(_txTex->name, _txTex->texture->name, 16);
		_txTex->width = _txTex->texture->width;
		_txTex->height = _txTex->texture->height;
		_txTex->mipmaps = 0;
		if(_txTex->texture->type - 8 > 0)
			_txTex->mipmaps = 8;
		_txTex->format = _txTex->texture->type - _txTex->mipmaps;
		
		if(_txTex->format == 6) {
			str_cpy(strT, _txTex->texture->name);
			str_cat(strT, ".dds");
			_txTex->buffer = _txTex->texture + 1;
			_txTex->bufSize = _txTex->width;
			add_buffer(strT->chars, _txTex->buffer, _txTex->bufSize);
			_txTex->bmap = bmap_create(strT->chars);
			_txTex->width = bmap_width(_txTex->bmap);
			_txTex->height = bmap_height(_txTex->bmap);
			add_buffer(strT->chars, NULL, _txTex->bufSize);
		} else {
			_txTex->bmap = bmap_createblack(_txTex->width, _txTex->height, texFormats[_txTex->format]);
			bmap_lock(_txTex->bmap, 0);
				_txTex->buffer = _txTex->texture + 1;
				_txTex->bufSize = _txTex->width * _txTex->height * _txTex->bmap->finalbytespp;
				memcpy(_txTex->bmap->finalbits, _txTex->buffer, _txTex->bufSize);
			bmap_unlock(_txTex->bmap);
		}
		
		_txTex->panel = pan_create("flags=SHOW", 1);
		_txTex->panel->pos_x = txtTextures->pos_x;
		_txTex->panel->pos_y = 28 + _index * 45;
		_txTex->panel->bmap = _txTex->bmap;
		_txTex->panel->scale_x = 32.0 / (var)_txTex->width;
		_txTex->panel->scale_y = 32.0 / (var)_txTex->height;
		
		str_printf(strT, "       Name: %s\n       Width:  %d\n       Height: %d\n       Type:   %d + %d", _txTex->name, _txTex->width, _txTex->height, _txTex->format, _txTex->mipmaps);
		txt_addstring(txtTextures, strT);
		txt_addstring(txtTextures, " ");
	}
}

void load_materials (TX_FILE *_txFile) {
	WMB_HEADER *_header = _txFile->buffer;
	
	_txFile->materials = _txFile->buffer + _header->materials.offset;
	_txFile->mtlCount = _header->materials.length / sizeof(MATERIAL_INFO);
	
	str_printf(strT, "Material count: %d", _txFile->mtlCount);
	txt_addstring(txtGlobal, strT);
	txt_addstring(txtGlobal, " ");
	
	MATERIAL_INFO *_mtl = _txFile->materials;
	long _index = 0;
	for(; _index < _txFile->mtlCount; _index += 1, _mtl += 1) {
		str_printf(strT, "Name: %s", _mtl->material);
		txt_addstring(txtMaterials, strT);
		txt_addstring(txtMaterials, " ");
	}
}

void load_info (TX_OBJECT *_txObject, WMB_INFO *_info) {
	_txObject->buffer = _info;
	
	_txObject->type = _info->type;
	txt_addstring(txtObjects, "WMB_INFO");
	
	str_printf(strT, "Sun azimuth: %.3f", (double)_info->azimuth);
	txt_addstring(txtObjects, strT);
	str_printf(strT, "Sun elevation: %.3f", (double)_info->elevation);
	txt_addstring(txtObjects, strT);
	str_printf(strT, "Gamma: %d", _info->gamma);
	txt_addstring(txtObjects, strT);
	
	char *_chrCol = &_info->dwSunColor;
	str_printf(strT, "Sun color: %d, %d, %d, %d", *(_chrCol++), *(_chrCol++), *(_chrCol++), *(_chrCol++));
	txt_addstring(txtObjects, strT);
	str_printf(strT, "Ambient color: %d, %d, %d, %d", *(_chrCol++), *(_chrCol++), *(_chrCol++), *(_chrCol++));
	txt_addstring(txtObjects, strT);
	str_printf(strT, "Fog 1 color: %d, %d, %d, %d", *(_chrCol++), *(_chrCol++), *(_chrCol++), *(_chrCol++));
	txt_addstring(txtObjects, strT);
	str_printf(strT, "Fog 2 color: %d, %d, %d, %d", *(_chrCol++), *(_chrCol++), *(_chrCol++), *(_chrCol++));
	txt_addstring(txtObjects, strT);
	str_printf(strT, "Fog 3 color: %d, %d, %d, %d", *(_chrCol++), *(_chrCol++), *(_chrCol++), *(_chrCol++));
	txt_addstring(txtObjects, strT);
	str_printf(strT, "Fog 4 color: %d, %d, %d, %d", *(_chrCol++), *(_chrCol++), *(_chrCol++), *(_chrCol++));
	txt_addstring(txtObjects, strT);
	
	txt_addstring(txtObjects, " ");
}

void load_position (TX_OBJECT *_txObject, WMB_POSITION *_pos) {
	_txObject->buffer = _pos;
	
	_txObject->type = _pos->type;
	txt_addstring(txtObjects, "WMB_POSITION");
	str_printf(strT, "Origin: %.3f,%.3f,%.3f", (double)_pos->origin[0], (double)_pos->origin[1], (double)_pos->origin[2]);
	txt_addstring(txtObjects, strT);
	
	txt_addstring(txtObjects, " ");
}

void load_light (TX_OBJECT *_txObject, WMB_LIGHT *_light) {
	_txObject->buffer = _light;
	
	_txObject->type = _light->type;
	txt_addstring(txtObjects, "WMB_LIGHT");
	str_printf(strT, "Origin: %.3f,%.3f,%.3f", (double)_light->origin[0], (double)_light->origin[1], (double)_light->origin[2]);
	txt_addstring(txtObjects, strT);
	
	txt_addstring(txtObjects, " ");
}

void load_sound (TX_OBJECT *_txObject, WMB_SOUND *_sound) {
	_txObject->buffer = _sound;
	
	_txObject->type = _sound->type;
	txt_addstring(txtObjects, "WMB_SOUND");
	str_printf(strT, "File: %s", _sound->filename);
	txt_addstring(txtObjects, strT);
	
	txt_addstring(txtObjects, " ");
}

void load_path (TX_OBJECT *_txObject, WMB_PATH *_path) {
	_txObject->buffer = _path;
	
	_txObject->type = _path->type;
	txt_addstring(txtObjects, "WMB_PATH");
	str_printf(strT, "Name: %s", _path->name);
	txt_addstring(txtObjects, strT);
	
	txt_addstring(txtObjects, " ");
}

void load_entity (TX_OBJECT *_txObject, WMB_ENTITY *_ent) {
	_txObject->buffer = _ent;
	
	_txObject->type = _ent->type;
	txt_addstring(txtObjects, "WMB_ENTITY");
	str_printf(strT, "File: %s", _ent->filename);
	txt_addstring(txtObjects, strT);
	
	txt_addstring(txtObjects, " ");
}

void load_old_entity (TX_OBJECT *_txObject, WMB_OLD_ENTITY *_ent) {
	
	_txObject->buffer = _ent;
	
	_txObject->type = _ent->type;
	txt_addstring(txtObjects, "WMB_OLD_ENTITY");
	str_printf(strT, "File: %s", _ent->filename);
	txt_addstring(txtObjects, strT);
	
	txt_addstring(txtObjects, " ");
}

void load_objects (TX_FILE *_txFile) {
	WMB_HEADER *_header = _txFile->buffer;
	
	long *_objOffArray = (long*)(_txFile->buffer + _header->objects.offset);
	_txFile->objCount = *_objOffArray;
	str_printf(strT, "Object count: %d", _txFile->objCount);
	txt_addstring(txtGlobal, strT);
	txt_addstring(txtGlobal, " ");
	
	_txFile->objects = sys_malloc(sizeof(TX_OBJECT) * _txFile->objCount);
	
	TX_OBJECT *_txObject = _txFile->objects;
	long *_objOff = _objOffArray + 1;
	long _index = 0;
	for(; _index < _txFile->objCount; _index += 1, _objOff += 1, _txObject += 1) {
		str_printf(strT, "ID: %d", _index);
		txt_addstring(txtObjects, strT);
		long *_objType = (long*)(((BYTE*)_objOffArray) + *_objOff);
		switch(*_objType) {
			case 1: //WMB_POSITION
				load_position(_txObject, _objType); 
				break;
			case 2: //WMB_LIGHT
				load_light(_txObject, _objType); 
				break;
			case 3: //WMB_OLD_ENTITY
				load_old_entity(_txObject, _objType); 
				break;
			case 4: //WMB_SOUND
				load_sound(_txObject, _objType); 
				break;
			case 5: //WMB_INFO
				_txFile->info = _txObject;
				load_info(_txObject, _objType); 
				break;
			case 6: //WMB_PATH
				load_path(_txObject, _objType); 
				break;
			case 7: //WMB_ENTITY
				load_entity(_txObject, _objType); 
				break;
			default:
				str_printf(strT, "type: %d", *_objType);
				txt_addstring(txtObjects, strT);
				txt_addstring(txtObjects, " ");
				
		}
	}
}

void load_lightmaps (TX_FILE *_txFile) {
	WMB_HEADER *_header = _txFile->buffer;
	
	long _width = 0;
	WMB_INFO *_info = _txFile->info->buffer;
	switch(_info->LMapSize) {
		case 0: _width = 256; break;  // 196608
		case 1: _width = 512; break;  // 786432
		case 2: _width = 1024; break; // 3145728
	}
	long _size = _width * _width * 3;
	_txFile->lmCount = _header->lightmaps.length / _size;
	
	str_printf(strT, "Lightmmap count: %d", _txFile->lmCount);
	txt_addstring(txtGlobal, strT);
	txt_addstring(txtGlobal, " ");
	
	_txFile->lightmaps = sys_malloc(sizeof(TX_LIGHTMAP) * _txFile->lmCount);
	
	TX_LIGHTMAP *_txLm = _txFile->lightmaps;
	BYTE *_buffer = _txFile->buffer + _header->lightmaps.offset;
	long _index = 0;
	for(; _index < _txFile->lmCount; _index += 1, _txLm += 1, _buffer += _size) {
		_txLm->buffer = _buffer;
		
		_txLm->bmap = bmap_createblack(_width, _width, 24);
		
		bmap_lock(_txLm->bmap, 0);
			BYTE *_bits = _txLm->bmap->finalbits;
			BYTE *_pBuf = _txLm->buffer;
			long _y = 0;
			for(; _y < _width; _y += 1) {
				long _x = 0;
				for(; _x < _width; _x += 1, _pBuf += 3, _bits += 4) {
					memcpy(_bits, _pBuf, 3);
					*(_bits + 3) = 255;
				}
			}
		bmap_unlock(_txLm->bmap);
		
		_txLm->panel = pan_create("flags=SHOW", 1);
		_txLm->panel->pos_x = txtLightmaps->pos_x;
		_txLm->panel->pos_y = txtLightmaps->pos_y + txtLightmaps->strings * 9 /*+ _index * 45*/;
		_txLm->panel->bmap = _txLm->bmap;
		_txLm->panel->scale_x = 32.0 / (var)_width;
		_txLm->panel->scale_y = 32.0 / (var)_width;
		
		str_printf(strT, "       ID: %d", _index);
		txt_addstring(txtLightmaps, strT);
		str_printf(strT, "       Width: %d", _width);
		txt_addstring(txtLightmaps, strT);
		str_printf(strT, "       Height: %d", _width);
		txt_addstring(txtLightmaps, strT);
//		txt_addstring(txtLightmaps, " ");
//		txt_addstring(txtLightmaps, " ");
//		txt_addstring(txtLightmaps, " ");
		txt_addstring(txtLightmaps, " ");
		
//		while(!key_space) {
//			DEBUG_BMAP(_txLm->bmap, txtLightmaps->pos_x + 160, 1);
//			wait(1);
//		}
//		key_pressed(-1);
//		wait(1);
		
	}
	
//	str_printf(strT, "%d\n%d", _header->lightmaps.offset, _header->lightmaps.length);
//	txt_addstring(txtLightmaps, strT);
//	txt_addstring(txtLightmaps, " ");
//	
//	str_printf(strT, "%d", _size);
//	txt_addstring(txtLightmaps, strT);
//	txt_addstring(txtLightmaps, " ");
//	
//	str_printf(strT, "LMapSize: %d", _info->LMapSize);
//	txt_addstring(txtLightmaps, strT);
//	txt_addstring(txtLightmaps, " ");
	
//	BMAP *_bmp = bmap_createblack(256, 256, 24);
//	var _frm = bmap_lock(_bmp, 0);
//	memcpy(_bmp->finalbits, _lmOffArray, 256*256*3);
//	bmap_unlock(_bmp);
//	
//	while(!key_space) {
//		DEBUG_BMAP(_bmp, 1, 1);
//		wait(1);
//	}
}

void load_lightmaps_terrain (TX_FILE *_txFile) {
	WMB_HEADER *_header = _txFile->buffer;
	
	long *_tlmOffArray = (long*)(_txFile->buffer + _header->lightmaps_terrain.offset);
	_txFile->tlmCount = *_tlmOffArray;
	str_printf(strT, "Lightmmap terrain count: %d", _txFile->tlmCount);
	txt_addstring(txtGlobal, strT);
	txt_addstring(txtGlobal, " ");
	
	txt_addstring(txtLightmaps, " ");
	txt_addstring(txtLightmaps, "TERRAIN LIGHTMAPS");
	txt_addstring(txtLightmaps, "--------------------");
	txt_addstring(txtLightmaps, " ");
	
	_txFile->terrain_lightmaps = sys_malloc(sizeof(TX_TERRAIN_LIGHTMAP) * _txFile->tlmCount);
	
	TX_TERRAIN_LIGHTMAP *_txLm = _txFile->terrain_lightmaps;
	BYTE *_buffer = _tlmOffArray + 1;
	long _index = 0;
	for(; _index < _txFile->tlmCount; _index += 1, _txLm += 1) {
		_txLm->lightmap_terrain = _buffer;
		_txLm->buffer = _txLm->lightmap_terrain + 1; //_buffer + sizeof(LIGHTMAP_TERRAIN); //
		
		long _size = _txLm->lightmap_terrain->width * _txLm->lightmap_terrain->height * 3;
		
//		if(_index == 1) {
//			_txLm->lightmap_terrain->object = 9;
//		}
		
		_txLm->bmap = bmap_createblack(_txLm->lightmap_terrain->width, _txLm->lightmap_terrain->height, 24);
		bmap_lock(_txLm->bmap, 0);
			BYTE *_bits = _txLm->bmap->finalbits;
			BYTE *_pBuf = _txLm->buffer;
			long _y = 0;
			for(; _y < _txLm->lightmap_terrain->height; _y += 1) {
				long _x = 0;
				for(; _x < _txLm->lightmap_terrain->width; _x += 1, _pBuf += 3, _bits += 4) {
					memcpy(_bits, _pBuf, 3);
					*(_bits + 3) = 255;
				}
			}
		bmap_unlock(_txLm->bmap);
		
		_txLm->panel = pan_create("flags=SHOW", 1);
		_txLm->panel->pos_x = txtLightmaps->pos_x;
		_txLm->panel->pos_y = txtLightmaps->pos_y + txtLightmaps->strings * 9 /*+ _index * 45*/;
		_txLm->panel->bmap = _txLm->bmap;
		_txLm->panel->scale_x = 32.0 / (var)_txLm->lightmap_terrain->width;
		_txLm->panel->scale_y = 32.0 / (var)_txLm->lightmap_terrain->height;
		
		str_printf(strT, "       Object ID: %d", _txLm->lightmap_terrain->object);
		txt_addstring(txtLightmaps, strT);
		str_printf(strT, "       Width: %d", _txLm->lightmap_terrain->width);
		txt_addstring(txtLightmaps, strT);
		str_printf(strT, "       Height: %d", _txLm->lightmap_terrain->height);
		txt_addstring(txtLightmaps, strT);
		txt_addstring(txtLightmaps, " ");
		
		
		
		
		_buffer = _txLm->buffer + _size;
		
//		while(!key_space) {
//			DEBUG_BMAP(_txLm->bmap, 1, 1);
//			wait(1);
//		}
//		key_pressed(-1);
//		wait(1);
	}
	
}

void load_blocks (TX_FILE *_txFile) {
	WMB_HEADER *_header = _txFile->buffer;
	
	long *_blkOffArray = (long*)(_txFile->buffer + _header->blocks.offset);
	_txFile->blkCount = *_blkOffArray;
	str_printf(strT, "Block count: %d", _txFile->blkCount);
	txt_addstring(txtGlobal, strT);
	txt_addstring(txtGlobal, " ");
	
	_txFile->blocks = sys_malloc(sizeof(TX_BLOCK) * _txFile->blkCount);
	
	TX_BLOCK *_txBlock = _txFile->blocks;
	BYTE *_buffer = _blkOffArray + 1;
	long _index = 0;
	for(; _index < _txFile->blkCount; _index += 1, _txBlock += 1) {
		_txBlock->block = _buffer;
		_buffer += sizeof(BLOCK);
		
		_txBlock->vertex = _buffer;
		_buffer += sizeof(VERTEX) * _txBlock->block->lNumVerts;
		
		_txBlock->tris = _buffer;
		_buffer += sizeof(TRIANGLE) * _txBlock->block->lNumTris;
		
		_txBlock->skins = _buffer;
		_buffer += sizeof(SKIN) * _txBlock->block->lNumSkins;
		
		str_printf(strT, "ID: %d", _index);
		txt_addstring(txtBlocks, strT);
		str_printf(strT, "Vertex: %d", _txBlock->block->lNumVerts);
		txt_addstring(txtBlocks, strT);
		str_printf(strT, "Triangles: %d", _txBlock->block->lNumTris);
		txt_addstring(txtBlocks, strT);
		str_printf(strT, "Skins: %d", _txBlock->block->lNumSkins);
		txt_addstring(txtBlocks, strT);
		txt_addstring(txtBlocks, " ");
	}
	
}

TX_FILE *load_level_file (char *_levelName) {
	if(!file_exists(_levelName)) {
		printf("file not found\n%s", _levelName);
		return NULL;
	}
	
	// main data struct
	TX_FILE *_txFile = sys_malloc(sizeof(TX_FILE));
	memset(_txFile, 0, sizeof(TX_FILE));
	
	// open file
	_txFile->buffer = file_load(_levelName, NULL, &_txFile->bufSize);
	
	// header
	WMB_HEADER *_header = _txFile->buffer;
	
	// version
	memcpy(_txFile->version, _header->version, 4);
	_txFile->version[4] = NULL;
	str_printf(strT, "Format version: %s", _txFile->version);
	txt_addstring(txtGlobal, strT);
	txt_addstring(txtGlobal, " ");
	if(_txFile->version[3] != 55) {
		txt_addstring(txtGlobal, "wrong wmb version");
		return _txFile;
	}
	
	// objects
	load_objects(_txFile);
	
	// blocks
	load_blocks(_txFile);
	
	// materials
	load_materials(_txFile);
	
	// textures
	load_textures(_txFile);
	
	// lightmaps
	load_lightmaps(_txFile);
	wait_for(load_lightmaps);
	
	// lightmaps terrain
	load_lightmaps_terrain(_txFile);
	
	
	
	txt_addstring(txtGlobal, "--------------------");
	txt_addstring(txtGlobal, " ");
	
	str_printf(strT, "objects:    %d - %d", _header->objects.offset, _header->objects.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "legacy7:    %d - %d", _header->legacy7.offset, _header->legacy7.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "legacy1:    %d - %d", _header->legacy1.offset, _header->legacy1.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "blocks:     %d - %d", _header->blocks.offset, _header->blocks.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "materials:  %d - %d", _header->materials.offset, _header->materials.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "textures:   %d - %d", _header->textures.offset, _header->textures.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "palettes:   %d - %d", _header->palettes.offset, _header->palettes.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "lightmaps:  %d - %d", _header->lightmaps.offset, _header->lightmaps.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "terrain lm: %d - %d", _header->lightmaps_terrain.offset, _header->lightmaps_terrain.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "bsp_leafs:  %d - %d", _header->bsp_leafs.offset, _header->bsp_leafs.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "bsp_nodes:  %d - %d", _header->bsp_nodes.offset, _header->bsp_nodes.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "aabb_hulls: %d - %d", _header->aabb_hulls.offset, _header->aabb_hulls.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "bsp_blocks: %d - %d", _header->bsp_blocks.offset, _header->bsp_blocks.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "pvs:        %d - %d", _header->pvs.offset, _header->pvs.length);
	txt_addstring(txtGlobal, strT);
	str_printf(strT, "            %d", _header->pvs.offset + _header->pvs.length);
	txt_addstring(txtGlobal, strT);
	



	str_printf(strT, "legacy2:    %d - %d", _header->legacy2.offset, _header->legacy2.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "legacy3:    %d - %d", _header->legacy3.offset, _header->legacy3.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "legacy4:    %d - %d", _header->legacy4.offset, _header->legacy4.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "legacy5:    %d - %d", _header->legacy5.offset, _header->legacy5.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "legacy6:    %d - %d", _header->legacy6.offset, _header->legacy6.length);
	txt_addstring(txtGlobal, strT);
	
	str_printf(strT, "legacy8:    %d - %d", _header->legacy8.offset, _header->legacy8.length);
	txt_addstring(txtGlobal, strT);
	
	txt_addstring(txtGlobal, " ");
	
	return _txFile;
}

void txFile_remove (TX_FILE *_txFile) {
	
//	TX_TEXTURE *_txTex = _txFile->textures;
//	long _index = 0;
//	for(; _index<_txFile->texCount; _index+=1, _txTex+=1) {
//		pan_remove(_txTex->panel);
//		bmap_remove(_txTex->bmap);
//	}
//	sys_free(_txFile->textures);
	
	file_load(NULL, _txFile->buffer, &_txFile->bufSize);
}

void main () {
	video_mode = 10;
	wait(3);
	on_esc = NULL;
	level_load("");
	camera->bg = pixel_for_vec(vector(0,0,0), 100, 888);
	
	TX_FILE *_txFile = load_level_file("scene.wmb");
	
	while(!key_esc) {
		wait(1);
	}
	
	file_save("scene_mod.wmb", _txFile->buffer, _txFile->bufSize);
	
	txFile_remove(_txFile);
	
	sys_exit(NULL);
}


Have fun!
Posted By: MooseMannequin

Re: Open/Extract Model and Textures from WMB - 12/30/20 16:20

Uuuuuh, what exactly should I do with this terrifying tree?
I read info in the link, at least now I know that, .WMB created in WED. I already tried import my .WMB there, it just says: "invalid file name" and that's it. But even if it'll open, I still don't get how to extract the model from .WMB.
I thought, it's gonna be something like .OBJ or other 3D type file haha. If it's gonna be the code, I have no use of it then. I need visual model.

And I made mistake, I said, that .WMB has model and textures. .WMB has the model only, the textures in .WTB files.
Thanks
Posted By: Dooley

Re: Open/Extract Model and Textures from WMB - 12/30/20 16:36

A WMB file is a game level, so it will contain 3D models as well as textures. However, WMB is the compiled level, not the editable level you would work on designing. I misread this part, and assumed you meant WMP, which is the editable level.

As WMB, it would be much more difficult to extract models and textures from it. txesmi's script, if I understand it correctly, would allow you to open a WMB and extract models/textures as you need, but if you are not familiar with how the engine works, and how to run scripts, then that might look intimidating.
Posted By: Quad

Re: Open/Extract Model and Textures from WMB - 12/30/20 18:31

Only level blocks are actually in the wmb file. Models/textures are separate files with the extension .mdl.
Models may be compressed in wrs though.
Posted By: MooseMannequin

Re: Open/Extract Model and Textures from WMB - 12/30/20 20:23

I understand, well, I can run scripts on "copy/paste, press Run" level haha, but I definitely not familiar with engines,
So, I think, I will try do this through Unity, but again I need to figure out how to use Python there, instead of C#, because the script WMB2OBJ that I found, written on Python language.
© 2024 lite-C Forums