Source Code
#include <bits/stdc++.h>
#include <windows.h>
using namespace std;
const int MAXN = 4e3;
struct colorInfo { int R, G, B; } array[MAXN][MAXN];
int N, M;
int size, tot = 0;
double len, scale;
struct bmp {
// save the information of bitmap
// partly from the Internet
unsigned char *pBmpBuf;
int bmpWidth;
int bmpHeight;
RGBQUAD *pColorTable;
int biBitCount;
// definitions
void read(char *filename) {
// read the bitmap under binary-read mode
FILE *fp = fopen(filename, "rb");
if (fp == NULL)
return ;
fseek(fp, sizeof(BITMAPFILEHEADER), 0);
BITMAPINFOHEADER head;
fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);
bmpWidth = head.biWidth;
bmpHeight = head.biHeight;
biBitCount = head.biBitCount;
N = bmpHeight, M = bmpWidth;
int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
if (biBitCount == 8) {
pColorTable = new RGBQUAD[256];
fread(pColorTable, sizeof(RGBQUAD), 256, fp);
}
pBmpBuf = new unsigned char[lineByte * bmpHeight];
fread(pBmpBuf, 1, lineByte * bmpHeight, fp);
fclose(fp);
return ;
}
void write(char *filename, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable) {
// write the color information into pixel_array.txt
// and generate a copy of the bitmap to debug
if (!imgBuf)
return ;
int colorTablesize = 0;
if (biBitCount == 8)
colorTablesize = 1024;
int lineByte = (width * biBitCount / 8 + 3) / 4 * 4;
FILE *fp = fopen(filename, "wb");
if (fp == NULL)
return ;
BITMAPFILEHEADER fileHead;
fileHead.bfType = 0x4D42;
fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte * height;
fileHead.bfReserved1 = 0;
fileHead.bfReserved2 = 0;
fileHead.bfOffBits = 54 + colorTablesize;
fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);
BITMAPINFOHEADER head;
head.biBitCount = biBitCount;
head.biClrImportant = 0;
head.biClrUsed = 0;
head.biCompression = 0;
head.biHeight = height;
head.biPlanes = 1;
head.biSize = 40;
head.biSizeImage = lineByte * height;
head.biWidth = width;
head.biXPelsPerMeter = 0;
head.biYPelsPerMeter = 0;
fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);
if (biBitCount == 8)
fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);
fwrite(imgBuf, height * lineByte, 1, fp);
fclose(fp);
return ;
}
void convert(char *filename) {
// proceed convertion
read(filename);
printf("[infor] Width: %d, Height: %d, biBitCount: %d.\n", bmpWidth, bmpHeight, biBitCount);
int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
int m = 0, n = 0, pixleCnt = 0;
ofstream outfile("pixel_array.txt", ios::in | ios::trunc);
if (biBitCount == 8) {
printf("[warning] received non-24-bit bmp. (exit without futher actions)\n");
int l1 = 0, x = 63, y = 0;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
for (l1 = x; l1 > x - 8; l1--)
for (int l2 = y; l2 < y + 8; l2++) {
m = *(pBmpBuf + l1 * lineByte + l2);
outfile << m << " ";
pixleCnt++;
if (pixleCnt % 3 == 0)
outfile << endl;
}
x = 63 - i * 8, y += 8;
}
x -= 8, y = 0;
}
}
if (!outfile) {
printf("[error] no such file found.");
exit(0);
} else if (biBitCount == 24) {
printf("[infor] received 24-bit bmp. Proceed to convert.\n");
for (int i = 0; i < bmpHeight; i++)
for (int j = 0; j < bmpWidth; j++, n++)
for (int k = 0; k < 3; k++) {
m = *(pBmpBuf + i * lineByte + j * 3 + k);
outfile << m << " ";
pixleCnt++;
switch (pixleCnt % 3) {
case 1: { array[i][j].R = m; break; }
case 2: { array[i][j].G = m; break; }
case 0: { array[i][j].B = m; outfile << endl; break; }
}
}
printf("[infor] total pixel number: %d\n", n);
}
char outpath[] = "copy.bmp";
write(outpath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
delete[] pBmpBuf;
if (biBitCount == 8)
delete[] pColorTable;
return ;
}
} pic;
inline int val(int src) { return min(int((src + 10) / 51), 4); }
// descrete the color
struct block {
// store the information of blocks
double x, y, z;
int id, materials;
block(double _x, double _y, double _z) { x = _x, y = _y, z = _z; }
block() {}
} blocks[MAXN][MAXN];
inline void generateBlocks() {
// convert the information in array[] to blocks[]
#define Rbase 0
#define Gbase 4
#define Bbase 8
#define BLACK 0
for (int i = 0; i < N * 2; i++)
for (int j = 0; j < M * 2; j++, tot++) {
int I = i / 2, J = j / 2;
blocks[i][j] = block(-(0.5 * i + 0.5) * scale, 0, (0.5 * j + 0.5) * scale);
switch ((i % 2) + (j % 2)) {
case 0: { // R
int v = val(array[I][J].R);
blocks[i][j].materials = v ? Rbase + v : BLACK;
break;
}
case 1: { // G
int v = val(array[I][J].G);
blocks[i][j].materials = v ? Gbase + v : BLACK;
break;
}
case 2: { // B
int v = val(array[I][J].B);
blocks[i][j].materials = v ? Bbase + v : BLACK;
break;
}
}
blocks[i][j].id = tot + 2;
}
return ;
}
namespace XML {
// functions to write the .xml file
// all written by myself
inline void generateBasicInfo() {
printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
printf("<Craft name=\"craft\" parent=\"\" initialBoundsMin=\"-0.8359594,-1.625213,-0.8359594\" initialBoundsMax=\"0.8359594,1.138787,0.8359594\" price=\"503000\" suppressCraftConfigWarnings=\"false\" xmlVersion=\"10\" localCenterOfMass=\"0,0,0\">\n");
printf(" <Assembly>\n");
printf(" <Parts>\n");
printf(" <Part id=\"1\" partType=\"CommandChip1\" position=\"0,0,0\" rotation=\"0,180,0\" rootPart=\"true\" commandPodId=\"1\" materials=\"0,1,2,3,4\">\n");
printf(" <Drag drag=\"1E-5,0.0001,0.0005,0.001,0,2E-5\" area=\"1E-05,0.0001,0.0005,0.001,1E-05,3E-05\" />\n");
printf(" <Config partScale=\"0.15,0.15,0.15\" />\n");
printf(" <CommandPod activationGroupNames=\",,,,,,,Landing Gear,Solar Panels,RCS\" activationGroupStates=\"false,false,false,false,false,false,false,true,false,true\" pidPitch=\"10,0,25\" pidRoll=\"10,0,25\" pilotSeatRotation=\"270,0,0\">\n");
printf(" <Controls />\n");
printf(" </CommandPod>\n");
printf(" </Part>\n");
return ;
}
inline void generateBlockInfo() {
for (int i = 0; i < N * 2; i++)
for (int j = 0; j < M * 2; j++) {
printf(" <Part id=\"%d\" partType=\"Block1\" position=\"%.5lf,%.5lf,%.5lf\" rotation=\"0,0,0\" name=\"%d-%d\" commandPodId=\"1\" materials=\"%d,1,2,3,4\">\n",
blocks[i][j].id, blocks[i][j].x, blocks[i][j].y, blocks[i][j].z, i, j, blocks[i][j].materials);
printf(" <Drag drag=\"0,0.002,0.002,0.001,0,0.002\" area=\"0,0.002,0.002,0.001,0,0.002\" />\n");
printf(" <Config partScale=\"%.2lf,%.2lf,%.2lf\" />\n", scale, scale, scale);
printf(" </Part>\n");
}
return ;
}
inline void generateConnectionInfo() {
printf(" </Parts>\n");
printf(" <Connections>\n");
for (register int i = 2; i < tot; i++)
printf(" <Connection partA=\"%d\" partB=\"%d\" attachPointsA=\"1\" attachPointsB=\"0\" />\n", i, i + 1);
printf(" </Connections>\n <Collisions />\n");
printf(" <Bodies>\n");
printf(" </Bodies>\n");
printf(" </Assembly>\n");
return ;
}
inline void generateColorInfo() {
printf(" <DesignerSettings themeName=\"Custom\">\n");
printf(" <Theme name=\"Custom\" id=\"3fe97eda-e2cd-4904-b2ab-15971ec8b516\">\n");
printf(" <Material color=\"000000\" m=\"0.1\" s=\"0.08\" />\n"); // BLACK
printf(" <Material color=\"000040\" m=\"0.1\" s=\"0.08\" />\n"); // R1
printf(" <Material color=\"000080\" m=\"0.1\" s=\"0.08\" />\n"); // R2
printf(" <Material color=\"0000C0\" m=\"0.1\" s=\"0.08\" />\n"); // R3
printf(" <Material color=\"0000FF\" m=\"0.1\" s=\"0.08\" />\n"); // R4
printf(" <Material color=\"002000\" m=\"0.1\" s=\"0.08\" />\n"); // G1 (half)
printf(" <Material color=\"004000\" m=\"0.1\" s=\"0.08\" />\n"); // G2 (half)
printf(" <Material color=\"006000\" m=\"0.1\" s=\"0.08\" />\n"); // G3 (half)
printf(" <Material color=\"008000\" m=\"0.1\" s=\"0.08\" />\n"); // G4 (half)
printf(" <Material color=\"400000\" m=\"0.1\" s=\"0.08\" />\n"); // B1
printf(" <Material color=\"800000\" m=\"0.1\" s=\"0.08\" />\n"); // B2
printf(" <Material color=\"C00000\" m=\"0.1\" s=\"0.08\" />\n"); // B3
printf(" <Material color=\"FF0000\" m=\"0.1\" s=\"0.08\" />\n"); // B4
printf(" <Material color=\"000000\" m=\"0.1\" s=\"0.08\" />\n");
printf(" <Material color=\"FFFFFF\" m=\"0.65\" s=\"0.08\" />\n </Theme>\n </DesignerSettings>\n");
printf(" <Themes>\n");
printf(" <Theme name=\"Custom\" id=\"78867b5d-f4ed-42a8-9566-6eef32bca546\">\n");
printf(" <Material color=\"000000\" m=\"0.1\" s=\"0.08\" />\n"); // BLACK
printf(" <Material color=\"000040\" m=\"0.1\" s=\"0.08\" />\n"); // R1
printf(" <Material color=\"000080\" m=\"0.1\" s=\"0.08\" />\n"); // R2
printf(" <Material color=\"0000C0\" m=\"0.1\" s=\"0.08\" />\n"); // R3
printf(" <Material color=\"0000FF\" m=\"0.1\" s=\"0.08\" />\n"); // R4
printf(" <Material color=\"002C00\" m=\"0.1\" s=\"0.08\" />\n"); // G1 (half)
printf(" <Material color=\"005800\" m=\"0.1\" s=\"0.08\" />\n"); // G2 (half)
printf(" <Material color=\"008400\" m=\"0.1\" s=\"0.08\" />\n"); // G3 (half)
printf(" <Material color=\"00B000\" m=\"0.1\" s=\"0.08\" />\n"); // G4 (half)
printf(" <Material color=\"400000\" m=\"0.1\" s=\"0.08\" />\n"); // B1
printf(" <Material color=\"800000\" m=\"0.1\" s=\"0.08\" />\n"); // B2
printf(" <Material color=\"C00000\" m=\"0.1\" s=\"0.08\" />\n"); // B3
printf(" <Material color=\"FF0000\" m=\"0.1\" s=\"0.08\" />\n"); // B4
printf(" <Material color=\"000000\" m=\"0.1\" s=\"0.08\" />\n");
printf(" <Material color=\"FFFFFF\" m=\"0.65\" s=\"0.08\" />\n");
printf(" </Theme>\n </Themes>\n <Symmetry />\n</Craft>\n");
// white balance is corrected
return ;
}
};
int main() {
// main function
printf("Maximum size supported: 2000 * 2000.\n");
printf("Please enter the filename ($filename$.bmp):\n > ");
char filename[1000];
scanf("%s", filename);
pic.convert(filename);
printf("Please enter the size of your picture in SimpleRockets2 (between 1 and 100):\n > ");
scanf("%d", &size);
scale = 1.0 * size / 100;
len = scale * 0.5;
generateBlocks();
freopen("craft.xml", "w", stdout);
XML::generateBasicInfo();
XML::generateBlockInfo();
XML::generateConnectionInfo();
XML::generateColorInfo();
cerr << "[infor] generated successfully.\n";
fclose(stdout);
return 0;
}
Usage
Step 1
Get a picture (requirement: 24-bit .bmp
file. Personally, I DO NOT recommend resolutions larger than 100 * 100, unless you have a really powerful processor) which you want to convert. Copy the source code above and save it in a .cpp
file.
Step 2
Put the picture and the cpp file in the same folder. Use Dev-Cpp
to compile the code (I did not test the code using other compilers). Run the .exe
file. Follow the instructions and you'll get a .xml
file in the same directory.
Step 3
Put the .xml
file in your craft data folder (generally at C:\Users\Username\AppData\LocalLow\Jundroo\SimpleRockets 2\UserData\CraftDesigns)
.