Archive 17/01/2023.

.txt to scene converter (v0.3) and bmp2txt

lexx

I made a little converter which converts .txt map file to urho3d scene .xml file.

txt2scene compiled .exe and sourcecodes: dropbox.com/s/wn0uqkr0ry2xe … rc.7z?dl=0
bmp2txt compiled .exe and sourcecodes: dropbox.com/s/fieybrfh62bg5 … xt.7z?dl=0

.txt map fileformat:

# test map file

mapSize: 15 7
blockSize: 1 1
model: 0 empty
model: 1 Plane
model: 2 Pyramid 0.2 4.0 0.2
model: 3 Sphere  0.5 0.5 0.5
model: 5 Box     1.0 2.0 1.0
model: x Torus

:floor
111111111111111
111111111111111
111111111111111
111111111111111
111111111111111
111111111111111
111111111111111

:wall
555555555555555
520002520000025
500000500333005
500x00500333005
500000000000005
52x3x252003x025
555555555555555

(I succesfully loaded above map (converted with txt2scene) to urho3d editor, no materials though)

model names are filenames without extension, ie
model: 3 Sphere is Models/Sphere.mdl

One can setup scale values to models ie
model: 3 Sphere 0.5 0.5 0.5

model: 0 empty <-- when empty, converter doesnt create node

:layerName <-- one can create multiple layers

Usage: txt2scene myskene.txt out.xml
txt2scene – binary
myskene.txt – map file descripted before
out.xml – urho3d scene, one can load this in editor

TODO:

  • better material handling? now it uses same material name as model name (ie Sphere.mdl uses Sphere.xml material)

ADDED:

  • node names

txt2scene.cpp :

/*
txt2scene
by mjt, 2014

Converts .txt map file to urho3d scene .xml file.

*/
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>
#include <string>
using namespace std;

class ModelInfo
{
public:
	char name[100];
	char ch;
	float xs, ys, zs;
};
ModelInfo modelInfo[1000];

void main(int argc, char **argv)
{
	if(argc<3)
	{
		printf("txt2scene by mjt, 2014\n");
		printf("Usage:\n %s  txtMapFileName  outputSceneFileName\n", argv[0]);
		return;
	}

	// open txt map file
	FILE *in=fopen(argv[1], "r");
	if(!in)
	{
		printf("Cannot open %s\n", argv[1]);
		return;
	}

#define MAX 1000
	char line[MAX];
	char mapName[MAX];
	int modelCounter=0;
	int width=0, height=0, blockWidth=0, blockHeight=0;
	float curX=0, curZ=0;
	string data=
		"<?xml version=\"1.0\"?>\n" \
		"<scene id=\"1\">\n" \
		"   <attribute name=\"Name\" value=\"\" />\n" \
		"   <attribute name=\"Time Scale\" value=\"1\" />\n" \
		"   <attribute name=\"Smoothing Constant\" value=\"50\" />\n" \
		"   <attribute name=\"Snap Threshold\" value=\"5\" />\n" \
/*		"   <attribute name=\"Elapsed Time\" value=\"7.3882\" />\n" \
		"   <attribute name=\"Next Replicated Node ID\" value=\"15\" />\n" \
		"   <attribute name=\"Next Replicated Component ID\" value=\"24\" />\n" \
		"   <attribute name=\"Next Local Node ID\" value=\"16777222\" />\n" \
		"   <attribute name=\"Next Local Component ID\" value=\"16777217\" />\n" \  
		"   <attribute name=\"Variables\" />\n" \
		"   <attribute name=\"Variable Names\" value=\"\" />\n" \  */
		"   <component type=\"Octree\" id=\"1\" />\n" \
		"   <component type=\"DebugRenderer\" id=\"2\" />\n";


	mapName[0]=0;
	int nodeID=1, compID=1;

	while(1)
	{
		if(fgets(line, MAX, in)==0)
			break;
		if(line[0]==0) 
			break;

		if(line[0]=='\n')
			continue;
		if(line[0]=='#') // comment
			continue;

		// map size
		if(memcmp(line, "mapSize:", 8)==0)
		{
			sscanf(line, "mapSize: %d %d", &width, &height);
			printf("mapSize: %d %d\n", width, height);

			continue;
		}

		if(memcmp(line, "blockSize:", 10)==0)
		{
			sscanf(line, "blockSize: %d %d", &blockWidth, &blockHeight);
			printf("blockSize: %d %d\n", blockWidth, blockHeight);

			continue;
		}

		// model name
		if(memcmp(line, "model:", 6)==0)
		{
			float xs=1, ys=1, zs=1;
			sscanf(line, "model: %c %s %f %f %f", 
				&modelInfo[modelCounter].ch, modelInfo[modelCounter].name, &xs, &ys, &zs);

			modelInfo[modelCounter].xs=xs;
			modelInfo[modelCounter].ys=ys;
			modelInfo[modelCounter].zs=zs;
			printf("model: %c = %s  (%8.2f, %8.2f, %8.2f)\n", 
				modelInfo[modelCounter].ch, modelInfo[modelCounter].name, xs, ys, zs);
		
			modelCounter++;

			continue;
		}

		// map name (ie floor, walls, furnitures)
		if(line[0]==':')
		{
			if(mapName[0]!=0)
				data+="   </node>\n";

			sscanf(line, ":%s\n", mapName);
			printf("name: %s\n", mapName);

			curX= -((float)width * (float)blockWidth)/2;
			curZ= -((float)height * (float)blockHeight)/2;

			char temp[100];
			sprintf(temp, "   <node id=\"%d\">\n", nodeID++);
			data+=temp;

			sprintf(temp, "   <attribute name=\"Name\" value=\"%s\" />\n", mapName);
			data+=temp;

			continue;
		}

		// parse map data
		for(int w=0; w<width; w++)
		{
			char *modelName="";
			float sx=1, sy=1, sz=1;
			for(int c=0; c<modelCounter; c++)
			{
				if(modelInfo[c].ch == line[w])
				{
					modelName = modelInfo[c].name;
					sx=modelInfo[c].xs;
					sy=modelInfo[c].ys;
					sz=modelInfo[c].zs;
					break;
				}
			}

			// dont add empty nodes
			if(memcmp(modelName, "empty", 5)==0)
			{
				curX += (float)blockWidth;
				continue;
			}

			char dta[10000];
			sprintf(dta, 
				"      <node id=\"%d\">\n" \
				"         <attribute name=\"Is Enabled\" value=\"true\" />\n" \
				"         <attribute name=\"Name\" value=\"%s\" />\n" \
				"         <attribute name=\"Position\" value=\"%8.2f %8.2f %8.2f\" />\n" \
				"         <attribute name=\"Rotation\" value=\"1 0 0 0\" />\n" \
				"         <attribute name=\"Scale\" value=\"%8.2f %8.2f %8.2f\" />\n" \
				"         <component type=\"StaticModel\" id=\"%d\">\n" \
				"            <attribute name=\"Model\" value=\"Model;Models/%s.mdl\" />\n" \
				"            <attribute name=\"Material\" value=\"Material;Materials/%s.xml;\" />\n" \
				"         </component>\n" \
				"      </node>\n",
					nodeID,
					modelName,
					curX, 0.f, curZ,
					sx, sy, sz,
					compID,
					modelName,
					modelName // material name
					);

			data = data + dta;

			nodeID++;
			compID++;

			curX += (float)blockWidth;
		}

		curX = -((float)width * (float)blockWidth)/2;
		curZ += (float)blockHeight;
	}

	fclose(in);

	data+= "   </node>\n";
	data+= "</scene>\n";

	// open output file
	FILE *out=fopen(argv[2], "w");
	if(!out)
	{
		printf("Cannot create %s\n", argv[1]);
		return;
	}
	fputs(data.c_str(), out);
	fclose(out);

}

NOTES:
Making txt maps can be slow so eggdrop.ch/projects/bmp2txt/index_en.htm
program what I just found (not made by me) converts 24-bit .bmp -> text, so making maps with Paint
is possible (might need some modifications if using lots of different colors(objects)).
EDIT: modified bmp2txt.cpp (can take 3 parameter, input_24bit.bmp output_mapfile.txt first_letter(which to use when creating .txt))

/* bmp2txt v0.1 Copyright (C) 2003 tomasliq <tom@eggdrop.ch>
 * 
 * A very simple bmp to text converter
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
// modified by mjt

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	FILE *file;
	unsigned short int filetype;
	long int offbits;
	int width, height;
	short int planes;
	short int bits;
	unsigned char *data, *linebuf;
	long size;
	char *outFileName="out.txt";
	char firstLetter='a';

	if (argc < 2)
	{
		printf("Usage: %s <bitmap>  (outFileName) (firstLetter) \n", argv[0]);
		exit(1);
	}
	if(argc>=3)
		outFileName=argv[2];

	if(argc>=4)
		firstLetter=argv[3][0];


	if ((file = fopen(argv[1], "rb")) == NULL)
	{
		printf("Error: Can not open file %s for reading\n", argv[1]);
		exit(1);
	}

	if (!fread(&filetype, sizeof(short int), 1, file))
	{
		printf("Error: Cannot read filetype\n");
		exit(1);
	}

	if (filetype != 19778)
	{
		printf("Error: This is not a bitmap file\n");
		exit(1);
	}
	
	fseek(file, 8, SEEK_CUR);

	if (!fread(&offbits, sizeof(long int), 1, file))
	{
		printf("Error: Cannot read offset\n");
		exit(1);
	}

	fseek(file, 4, SEEK_CUR);

	fread(&width, sizeof(int), 1, file);
	fread(&height, sizeof(int), 1, file);
	
	fread(&planes, sizeof(short int), 1, file);
	
	if (planes != 1)
	{
		printf("Error: Number of planes must be 1\n");
		exit(1);
	}

	if (!fread(&bits, sizeof(short int), 1, file))
	{
		printf("Error: Cannot read bits\n");
	}

	if (bits != 24)
	{
		printf("Error: Number of bits per pixel must be 24\n");
		exit(1);
	}

	size = width*height*3;

	linebuf = (unsigned char *)malloc(width*3);
	
	if ((data = (unsigned char *)malloc(size)) == NULL)
	{
		printf("Error: Cannot allocate memory\n");
		exit(1);
	}

	
	fseek(file, offbits, SEEK_SET);
	
	if (!fread(data, size, 1, file))
	{
		printf("Error: Cannot read bitmap data\n");
		exit(1);
	}

	fclose(file);

	FILE *out = fopen(outFileName, "w");
	if(!out)
	{
		printf("Error: Can not open file %s for writing\n", argv[1]);
		exit(1);
	}

	int difcols=1;
	long ch[1000];   // different characters
	long cols[1000]; // different colors
	cols[0]=cols[1]=cols[2]=0;
	ch[0]=' ';

	// convert colors to characters
	int x,y;
	for (y=(height-1)*3; y>0; y-=3)
	{
		for (x=0; x<width*3; x+=3)
		{
			long pos=y*width + x;
			long c = (data[pos]<<16) + (data[pos+1]<<8) + data[pos+2];


			int cc=0;
			char found=0;
			// check color
			for(cc=0; cc<difcols; cc++)
			{
				if(cols[cc]==c)
				{
					found=1;
					break;
				}
			}

			if(found)
			{
				fprintf(out, "%c", ch[cc]);
			}
			else
			{
				ch[difcols]=firstLetter + (difcols-1);
				cols[difcols]=c;

				fprintf(out, "%c", ch[difcols]);
				difcols++;
			}

		}
		fprintf(out, "\n");
	}
	free(data);
	fclose(out);

	return 0;
}