Thread: How To Incorporate input_byte In For Loop Query ?

  1. #46
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john c.

    I will try and find out, some information, as regards the RLE asap, and get an suitable image, of the cockpit view. Many thanks for all you have done, so far as regards this thread. It is much appreciated.

    Eddie

  2. #47
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john.c,

    I typed what you said, I should, type on the command line in Visual Studio, and all that happens is Hello World ! is outputted, and nothing is done to the P51DD.PNL File. I am not sure why that is the case ? Could you suggest where I have gone wrong ? I have attached an Screenshot, of the ME110 Cockpit view as a Jpeg File.

    I have remembered something, that the person who wrote the original Code said.
    He said that some Files, might have more than one image in, as DOS Games had different graphics Formats, i.e. CGA, EGA, VGA, MCGA etc, so that is probably why the P51DD.PNL File had another image output ?

    Best Regards

    Eddie Winch
    Attached Images Attached Images How To Incorporate input_byte In For Loop Query ?-me110-jpg 
    Last edited by eddywinch82; 01-18-2023 at 09:57 AM.

  3. #48
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Comparing that picture to the mangled output gave me an idea and it looks like I figured it out. Apparently the older game used only 32 grayscale values instead of 64. So the single-byte values have a 3-bit count instead of a 2-bit count. Changing the code to account for that (and modifying the bmp palette) currently gives the following. I will try to figure out the correct palette tonight (or later today if I get some time).

    It would be useful if you could upload a better shot of the ME110 cockpit.
    Just grab the window, not the entire desktop (presumably there's a way to do that).
    And save it as a png or gif (losseless compression), not a jpg (lossy compression).

    How To Incorporate input_byte In For Loop Query ?-110dash-out0-png
    A little inaccuracy saves tons of explanation. - H.H. Munro

  4. #49
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john c.

    I am amazed by what you have done well done ))

    Here is a better .png screenshot :-
    Attached Images Attached Images How To Incorporate input_byte In For Loop Query ?-me110-png 

  5. #50
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john.c,

    How are you getting on with this ?

    Eddie

  6. #51
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    The PNL files you've given us contain 4 chunks.
    The first seems to be a smallish fairly simple image but I can't decode it.
    The second is the cockpit image.
    The third and forth chunks contain palettes of 64 colors and some other data that I can't decipher (and are the same as each other).
    Applying the palette to the image yields this:

    How To Incorporate input_byte In For Loop Query ?-p51dd-out1-png

    The PAC file does not contain a palette so I don't know how to set it's palette of 32 colors correctly.

    I call the older file V1 files and the newer ones V2 files.
    This is the current program.
    If the program is called pacdump:
    $ pacdump 110DASH.PAC # process file as V1
    $ pacdump -n P51BD.PNL # process file as V2 (default gray palette)
    $ pacdump -n -p2 P51BD.PNL # process file as V2 using chunk 2 as palette
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <limits.h>
     
    #define MAX_W   600
    #define MAX_H   300
     
    #define HEADER_SIZE     54
    #define PALETTE_ENTRIES 256
    #define PALETTE_SIZE    (PALETTE_ENTRIES * 4)   // 4 bytes per entry
    #define DATA_OFFSET     (HEADER_SIZE + PALETTE_SIZE)
     
    typedef unsigned char Byte;
    typedef enum Mode { V1, V2 } Mode; // V1 for older files, V2 for newer
     
    typedef struct Info {
        Byte image[MAX_H][MAX_W];
        int  min_width, max_width;
        int  width, height;
        int  adder;
        int  output_file_index;
        int  n_palette;
        const char *filename;
    } Info;
     
    Info info = {
        .min_width = INT_MAX,
        .n_palette = -1,
        .filename  = NULL
    };
    Mode ProgramMode = V1;
     
    void reset() {
        memset(info.image, 0, MAX_H * MAX_W);
        info.min_width = INT_MAX;
        info.max_width = 0;
        info.width = 0;
        info.height = 0;
        info.adder = 0;
    }
     
    void default_palette(Byte *pal) {
        const int shift = (ProgramMode == V1 ? 3 : 2);
        for (int color = 0; color < PALETTE_ENTRIES; color++) {
            *pal++ = color << shift;
            *pal++ = color << shift;
            *pal++ = color << shift;
            *pal++ = 0;
        }
    }
     
    void fill_palette(Byte *pal, const char *infilename, int n_palette) {
        if (n_palette == -1) {
            default_palette(pal);
            return;
        }
        FILE *f = fopen(infilename, "rb");
        int byte, cnt = 0;
        const int shift = (ProgramMode == V1 ?  3 :  2);
        const int size  = (ProgramMode == V1 ? 32 : 64);
        while ((byte = fgetc(f)) != EOF) {
            if (byte == 0xFF && ++cnt == n_palette) {
                for (int i = 0; i < size; ++i) {
                    int r = fgetc(f), g = fgetc(f), b = fgetc(f);
                    pal[i * 4    ] = b << shift;
                    pal[i * 4 + 1] = g << shift;
                    pal[i * 4 + 2] = r << shift;
                }
                break;
            }
        }
        fclose(f);
    }
     
    void save_bmp() { 
        Byte header[HEADER_SIZE] = {
            0x42, 0x4D,                  //  0: BM signature
              -1,   -1,   -1,   -1,      //  2: filesize
               0,    0,    0,    0,      //  6: reserved
              -2,   -2,   -2,   -2,      // 10: offset to pixel array
            0x28,    0,    0,    0,      // 14: DIB header size
              -3,   -3,   -3,   -3,      // 18: width
              -4,   -4,   -4,   -4,      // 22: height
            0x01,    0,                  // 26: planes
            0x08,    0                   // 28: bits per pixel
        };
     
        int pad = (4 - info.max_width % 4) % 4;
        int file_size = DATA_OFFSET + (info.max_width + pad) * info.height;
        Byte *output = malloc(file_size);
        memcpy(output, header, HEADER_SIZE);
        *(int*)(output +  2) =  file_size;
        *(int*)(output + 10) =  DATA_OFFSET;
        *(int*)(output + 18) =  info.max_width;
        *(int*)(output + 22) = -info.height;
     
        Byte *pal = output + HEADER_SIZE;
        if (info.n_palette == -1)
            default_palette(pal);
        else
            fill_palette(pal, info.filename, info.n_palette);
    
        for (int h = 0, pos = DATA_OFFSET; h < info.height; h++) {
            for (int w = 0; w < info.max_width; w++)
                output[pos++] = info.image[h][w];
            for (int p = 0; p < pad; p++)
                output[pos++] = 0;
        }
     
        // Output filenames are: filename-outN.bmp where N is 0,1,...
        char outfilename[100];
        strcpy(outfilename, info.filename);
        char *p = strrchr(outfilename, '.');
        if (p) *p = '\0';
        sprintf(outfilename + strlen(outfilename), "-out%d.bmp",
            info.output_file_index);
     
        FILE *f = fopen(outfilename, "wb");
        fwrite(output, 1, file_size, f);
        fclose(f);
     
        free(output);
    }
     
    void add(int value) {
        if (info.height < MAX_H && info.width < MAX_W)
            info.image[info.height][info.width++] = value;
    }
     
    void process(FILE *fp) {
        for (int byte, prev = 0xFF; (byte = fgetc(fp)) != EOF; prev = byte) {
            int count, value;
            if (prev == 0xFF)
                printf("Chunk: %d\n", info.output_file_index);
            switch (byte) {
            case 0xFF: // End of image
                if (prev == 0xFE) {
                    if (info.min_width != info.max_width)
                        printf("  Error: min (%d) and max (%d) widths do not match\n",
                            info.min_width, info.max_width);
                    printf("  Width: %d  Height: %d\n", info.max_width, info.height);
                    save_bmp();
                }
                reset();
                ++info.output_file_index;
                break;
            case 0xFE: // End of image line
                if (info.width < info.min_width) info.min_width = info.width;
                if (info.width > info.max_width) info.max_width = info.width;
                ++info.height;
                info.width = 0;
                break;
            case 0xFD: // next two bytes are count-1 and value
                count = fgetc(fp) + 1;
                value = fgetc(fp);
                for (int i = 0; i < count; ++i) add(value);
                break;
            case 0xFC: // next two bytes are count-1 and value
                value = fgetc(fp);  // orig. code had +1 here (but why?)
                count = fgetc(fp) + 1;
                for (int i = 0; i < count; ++i) // draw dithered line
                    add(i % 2 == 0 ? value : value + 1);
                break;
            case 0xFB: // Set adder used in default case
                info.adder = fgetc(fp);
                break;
            default:
                if (ProgramMode == V1) {
                    value = (byte >> 3) + info.adder; // High 5 bits are value
                    count = (byte & 7) + 1;           // Low 3 bits are count-1
                }
                else {
                    value = (byte >> 2) + info.adder; // High 6 bits are value
                    count = (byte & 3) + 1;           // Low 2 bits are count-1
                }
                for (int i = 0; i < count; ++i) add(value);
            }
        }
    }
     
    int main(int argc, char *argv[]) {
        if (argc < 2 || argc > 5) {
            printf("Usage: %s [-n] [-p N] INPUT_FILE\n", argv[0]);
            exit(EXIT_FAILURE);
        }
     
        while (**++argv == '-') {
            if (strcmp(*argv, "-n") == 0)
                ProgramMode = V2;
            else if (strncmp(*argv, "-p", 2) == 0) {
                if (argv[0][2])
                    info.n_palette = atoi(&argv[0][2]);
                else {
                    if (*++argv == NULL) {
                        fprintf(stderr, "Error: Missing parameters\n");
                        exit(EXIT_FAILURE);
                    }
                    info.n_palette = atoi(*argv);
                }
            }
            else {
                fprintf(stderr, "Error: Unknown switch: %s\n", *argv);
                exit(EXIT_FAILURE);
            }
        }
     
        if (!*argv) {
            fprintf(stderr, "Error: No filename\n");
            exit(EXIT_FAILURE);
        }
        info.filename = *argv;
        FILE *fp = fopen(info.filename, "rb");
        if (!fp) {
            perror(info.filename);
            exit(EXIT_FAILURE);
        }
      
        process(fp);
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  7. #52
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john.c,

    You are amazing, I wish I had your coding skills, thankyou so much, for what you done so far.

    I was just wondering, could you alter the latest code, so that multiple files, can be processed at the same time from a certain folder ? Like with the original code I posted ? And be able to save the output files to a folder of choice ?

    Or would I use *.PNL to process all files ?

    Regards

    Eddie Winch ))

  8. #53
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    It would be interesting if you could upload a couple more examples of each type of file.
    Here's a version of the program that can process multiple files and put them into a given directory.
    The directory is given after the -d flag (abc in the e.g.).

    $ pacdump -n -p 2 -d abc *.PNL # decode all PNL file to directory abc
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <limits.h>
     
    #define MAX_W   600
    #define MAX_H   300
     
    #define HEADER_SIZE     54
    #define PALETTE_ENTRIES 256
    #define PALETTE_SIZE    (PALETTE_ENTRIES * 4)   // 4 bytes per entry
    #define DATA_OFFSET     (HEADER_SIZE + PALETTE_SIZE)
     
    typedef unsigned char Byte;
     
    typedef struct Info {
        Byte image[MAX_H][MAX_W];
        int  min_width, max_width;
        int  width, height;
        int  adder;
        int  output_file_index;
        int  n_palette;
        const char *filename;
        const char *dirname;
    } Info;
     
    Info info = {
        .min_width = INT_MAX,
        .n_palette = -1,
        .filename  = NULL,
        .dirname   = NULL
    };
     
    int version = 1; // 1 for older files, 2 for newer
     
    void reset() {
        memset(info.image, 0, MAX_H * MAX_W);
        info.min_width = INT_MAX;
        info.max_width = 0;
        info.width = 0;
        info.height = 0;
        info.adder = 0;
    }
     
    void default_palette(Byte *pal) {
        const int shift = (version == 1 ? 3 : 2);
        for (int color = 0; color < PALETTE_ENTRIES; color++) {
            *pal++ = color << shift;
            *pal++ = color << shift;
            *pal++ = color << shift;
            *pal++ = 0;
        }
    }
     
    void fill_palette(Byte *pal, const char *infilename, int n_palette) {
        if (n_palette == -1) {
            default_palette(pal);
            return;
        }
        FILE *f = fopen(infilename, "rb");
        int byte, cnt = 0;
        const int shift = (version == 1 ?  3 :  2);
        const int size  = (version == 1 ? 32 : 64);
        while ((byte = fgetc(f)) != EOF) {
            if (byte == 0xFF && ++cnt == n_palette) {
                for (int i = 0; i < size; ++i) {
                    int r = fgetc(f), g = fgetc(f), b = fgetc(f);
                    pal[i * 4    ] = b << shift;
                    pal[i * 4 + 1] = g << shift;
                    pal[i * 4 + 2] = r << shift;
                }
                break;
            }
        }
        fclose(f);
    }
     
    void save_bmp() { 
        Byte header[HEADER_SIZE] = {
            0x42, 0x4D,                  //  0: BM signature
              -1,   -1,   -1,   -1,      //  2: filesize
               0,    0,    0,    0,      //  6: reserved
              -2,   -2,   -2,   -2,      // 10: offset to pixel array
            0x28,    0,    0,    0,      // 14: DIB header size
              -3,   -3,   -3,   -3,      // 18: width
              -4,   -4,   -4,   -4,      // 22: height
            0x01,    0,                  // 26: planes
            0x08,    0                   // 28: bits per pixel
        };
     
        int pad = (4 - info.max_width % 4) % 4;
        int file_size = DATA_OFFSET + (info.max_width + pad) * info.height;
        Byte *output = malloc(file_size);
        memcpy(output, header, HEADER_SIZE);
        *(int*)(output +  2) =  file_size;
        *(int*)(output + 10) =  DATA_OFFSET;
        *(int*)(output + 18) =  info.max_width;
        *(int*)(output + 22) = -info.height;
     
        Byte *pal = output + HEADER_SIZE;
        if (info.n_palette == -1)
            default_palette(pal);
        else
            fill_palette(pal, info.filename, info.n_palette);
    
        for (int h = 0, pos = DATA_OFFSET; h < info.height; h++) {
            for (int w = 0; w < info.max_width; w++)
                output[pos++] = info.image[h][w];
            for (int p = 0; p < pad; p++)
                output[pos++] = 0;
        }
     
        // Output filenames are: filename-outN.bmp where N is 0,1,...
        char outfilename[100];
        strcpy(outfilename, info.dirname);
        strcat(outfilename, "/");
        strcat(outfilename, info.filename);
        char *p = strrchr(outfilename, '.');
        if (p) *p = '\0';
        sprintf(outfilename + strlen(outfilename), "-out%d.bmp",
            info.output_file_index);
     
        // Make the directory if it doesn't exist (mkdir is same on Windows and linux)
        char cmd[100];
        sprintf(cmd, "mkdir %s", info.dirname);
        system(cmd);
     
        FILE *f = fopen(outfilename, "wb");
        fwrite(output, 1, file_size, f);
        fclose(f);
     
        free(output);
    }
     
    void add(int value) {
        if (info.height < MAX_H && info.width < MAX_W)
            info.image[info.height][info.width++] = value;
    }
     
    void process(FILE *fp) {
        printf("File: %s\n", info.filename);
        for (int byte, prev = 0xFF; (byte = fgetc(fp)) != EOF; prev = byte) {
            int count, value;
            if (prev == 0xFF)
                printf("  Chunk: %d\n", info.output_file_index);
            switch (byte) {
            case 0xFF: // End of image
                if (prev == 0xFE) {
                    if (info.min_width != info.max_width)
                        printf("    Error: min (%d) and max (%d) widths do not match\n",
                            info.min_width, info.max_width);
                    printf("    Width: %d  Height: %d\n", info.max_width, info.height);
                    save_bmp();
                }
                reset();
                ++info.output_file_index;
                break;
            case 0xFE: // End of image line
                if (info.width < info.min_width) info.min_width = info.width;
                if (info.width > info.max_width) info.max_width = info.width;
                ++info.height;
                info.width = 0;
                break;
            case 0xFD: // next two bytes are count-1 and value
                count = fgetc(fp) + 1;
                value = fgetc(fp);
                for (int i = 0; i < count; ++i) add(value);
                break;
            case 0xFC: // next two bytes are value and count-1
                value = fgetc(fp);  // orig. code had +1 here (but why?)
                count = fgetc(fp) + 1;
                for (int i = 0; i < count; ++i) // draw dithered line
                    add(i % 2 == 0 ? value : value + 1);
                break;
            case 0xFB: // Set adder used in default case
                info.adder = fgetc(fp);
                break;
    //        case 0xFA: // chunk 0 of the PNL files use this
    //            break; // but I don't know what it does
            default:
                if (version == 1) {
                    value = (byte >> 3) + info.adder; // High 5 bits are value
                    count = (byte & 7) + 1;           // Low 3 bits are count-1
                }
                else {
                    value = (byte >> 2) + info.adder; // High 6 bits are value
                    count = (byte & 3) + 1;           // Low 2 bits are count-1
                }
                for (int i = 0; i < count; ++i) add(value);
            }
        }
    }
     
    int main(int argc, char *argv[]) {
        if (argc < 2) {
            printf("Usage: %s [-n] [-p N] [-d DIRECTORY] INPUT_FILE\n", argv[0]);
            exit(EXIT_FAILURE);
        }
     
        while (**++argv == '-') {
            if (strcmp(*argv, "-n") == 0)
                version = 2;
            else if (strncmp(*argv, "-p", 2) == 0) {
                if (argv[0][2])
                    info.n_palette = atoi(&argv[0][2]);
                else {
                    if (*++argv == NULL) {
                        fprintf(stderr, "Error: Missing parameters\n");
                        exit(EXIT_FAILURE);
                    }
                    info.n_palette = atoi(*argv);
                }
            }
            else if (strncmp(*argv, "-d", 2) == 0) {
                if (argv[0][2])
                    info.dirname = &argv[0][2];
                else {
                    if (*++argv == NULL) {
                        fprintf(stderr, "Error: Missing parameters\n");
                        exit(EXIT_FAILURE);
                    }
                    info.dirname = *argv;
                }
            }
            else {
                fprintf(stderr, "Error: Unknown switch: %s\n", *argv);
                exit(EXIT_FAILURE);
            }
        }
     
        if (!*argv) {
            fprintf(stderr, "Error: No filename\n");
            exit(EXIT_FAILURE);
        }
     
        for ( ; *argv; ++argv) {
            info.output_file_index = 0;
    
            info.filename = *argv;
            FILE *fp = fopen(info.filename, "rb");
            if (!fp) {
                perror(info.filename);
                exit(EXIT_FAILURE);
            }
          
            process(fp);
     
            fclose(fp);
        }
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  9. #54
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john.c,

    Here I have Uploaded, 4 Files as a .zip File. The .PAC Files are the German and British Fighter Aircraft Dashboard Files, from Their Finest Hour. And the two .PNL Files, are the BF109 Dashboard and FW190 Dashboard Files, from Secret Weapons Of The Luftwaffe.

    Eddie )
    Attached Files Attached Files

  10. #55
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john.c,

    I built the program as a c one, but when I run the Program from the Command Line in Visual Studio, it just outputs Hello World !, no Folder is created with output Files etc, could you tell me what I am doing wrong ?

    Regards

    Eddie Winch )

  11. #56
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Obviously it makes no sense for it to print Hello World, so you must be running the wrong program. I have no idea what you are doing wrong.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  12. #57
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john.c,

    I have sorted the problem now, I tried compiling the program from the command line, and it works now, what should I type to select all files i.e. *.PNL from a directory i.e. pnl ?

    I use from the command prompt, or the command line in Visual Studio :-

    pac-misc -n -p 2 -d raw2 *.PNL

    It didn't work with the $ in front of pac-misc

    but it says :-

    *.PNL: Invalid argument

    The program works, with individual .PNL Files though.
    Last edited by eddywinch82; 01-20-2023 at 06:29 PM.

  13. #58
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    It didn't work with the $ in front of pac-misc
    This is painful.
    I'm taking a break.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  14. #59
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    This worked for BFDASH.PAC :-

    pac-misc -d raw1 BFDASH.PAC

    And this worked for HE162D.PNL :-

    pac-misc -n -p 2 -d raw2 HE162D.PNL

    And I have attached the output .bmp Files,

    From BFDASH.PAC and BFLWING.PAC

    British Fighters Dashboard and Left Wing Views :-


    Attached Images Attached Images How To Incorporate input_byte In For Loop Query ?-bfdash-out0-bmp How To Incorporate input_byte In For Loop Query ?-bflwing-out0-bmp 
    Last edited by eddywinch82; 01-20-2023 at 07:49 PM.

  15. #60
    Registered User
    Join Date
    Jan 2023
    Posts
    39
    Hi john.c,

    I have attached two .zip Files, one is from the game Battlehawks 1942 i.e BH1942, which was the first game in the WW2 Game trilogy. The two Files, have the same output .bmp issue as there was, in the game Their Finest Hour with the 110DASH.PAC File. The other .zip File, has two files from Their Finest Hour, i.e. BOB1940 with the same issue, could you analyse the files, and fix that issue for me, if that is okay ?

    Also could you find a way, to work on all files at once ? as *.PAC or *.PNL doesn't work, producing an error. And be able to process the files, when they are in another directory ?

    Regards

    Eddie Winch
    Attached Files Attached Files

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. While Loop Query - code displayed
    By darren78 in forum C Programming
    Replies: 13
    Last Post: 02-17-2009, 10:44 AM
  2. first look incorporate assembly?
    By stabu in forum C Programming
    Replies: 8
    Last Post: 09-25-2008, 08:53 AM
  3. Loop Query
    By (TNT) in forum C# Programming
    Replies: 5
    Last Post: 02-13-2006, 06:16 PM
  4. How can I incorporate this code into a web page?
    By MisterRob in forum C Programming
    Replies: 6
    Last Post: 11-02-2005, 05:43 PM
  5. Best way to incorporate upgrades
    By Shadow12345 in forum A Brief History of Cprogramming.com
    Replies: 3
    Last Post: 09-26-2002, 07:41 AM

Tags for this Thread