To boldly go where no one has gone before.

【退役生活】SimpleRockets2

2020-01-12 17:09:48


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).

All Done!