8-Bit RLE Bitmap wird nicht richtig geladen.
-
Hallo Leute und Benutzer'inen des Forum's.
Ich bin neu hier, weil ich ein Spezifisches Problem bei der Dekompression eines 8Bit bmp Files habe.
Ich bin via google auf das Forum gestoßen weil irgendwer ein Padding Problem beim einlesen eines bmp Files hatte.Das Projekt an dem ich arbeite ist etwas umfangreicher, denn es ist ein Video Spiel für die Playstation 2.
Mich Fasziniert die Hardware der PS2 schon seit 20 Jahren, aber bisher hatte ich keine Zeit so ein Umfangreiches Projekt in die Hand zu nehmen.Bevor es zu den eigentlichen Problem geht, ich Portiere ein altbekanntes 2D Spiel auf die PS2.
Das Spiel gibt es nur für Windows, aber ich möchte so wenig wie möglich vom Original Spiel verändern. Daher will ich die ordinalen bmp Datei die im 8Bit Format RLE Komprimiert sind beibehalten.Das Problem ist, das der RLE Algorithmus einige Bilder verstümmelt, einige Bilder werden aber korrekt dargestelt.
Hier ist der C-Code:#include "rlec.h" void free_RLE(); uint32_t RLE_getDataSize(); uint16_t RLE_get_height(); void printHeader(_bitmap *image); uint16_t RLE_get_width(); void RLE_get_pixel_rgb(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a); int RLEDecompression(const char *filePath); _bitmap *image = NULL; uint8_t *pallet = NULL; uint8_t *data = NULL; void printHeader(_bitmap *image) { fprintf(stdout, "\tMagic number: %c%c\n", image->magicNumber[0], image->magicNumber[1]); fprintf(stdout, "\tSize: %u\n", image->size); fprintf(stdout, "\tReserved: %u %u %u %u\n", image->reserved[0], image->reserved[1], image->reserved[2], image->reserved[3]); fprintf(stdout, "\tStart offset: %u\n", image->startOffset); fprintf(stdout, "\tHeader size: %u\n", image->headerSize); fprintf(stdout, "\tWidth: %u\n", image->width); fprintf(stdout, "\tHeight: %u\n", image->height); fprintf(stdout, "\tPlanes: %u\n", image->planes); fprintf(stdout, "\tDepth: %u\n", image->depth); fprintf(stdout, "\tCompression: %u\n", image->compression); fprintf(stdout, "\tImage size: %u\n", image->imageSize); fprintf(stdout, "\tX pixels per meters: %u\n", image->xPPM); fprintf(stdout, "\tY pixels per meters: %u\n", image->yPPM); fprintf(stdout, "\tNb of colors used: %u\n", image->nUsedColors); fprintf(stdout, "\tNb of important colors: %u\n", image->nImportantColors); } void printPalette(uint8_t *pallet, int paletteSize) { for (int i = 0; i < paletteSize; i += 4) // Palette hat 4 Byte pro Farbe (B, G, R, A) { printf("Palette[%d]: B=%u, G=%u, R=%u, A=%u\n", i / 4, pallet[i], pallet[i+1], pallet[i+2], pallet[i+3]); } } void printData(uint8_t *data, int dataSize) { for (int i = 0; i < dataSize; i++) { printf("Data[%d]: %u\n", i, data[i]); if(i > 100){ return; } } } bool validate_row_lengths() { // Berechnung der tatsächlichen Breite (in Bytes), unter Berücksichtigung des Paddings int paddedRowSize = ((image->width + 3) / 4) * 4; // Vergleich der berechneten Größe mit der Bildgröße if (image->imageSize != paddedRowSize * image->height) { return false; } return true; } int RLEDecompression(const char *filePath) { uint32_t i, j, total = 0, lecture = 0; uint8_t couples[2]; FILE* ptrIn = fopen(filePath, "rb"); if (ptrIn == NULL) { fprintf(stderr, "Error: Cannot open file %s\n", filePath); return -1; // oder eine andere geeignete Fehlerbehandlung } /* Reading the file */ image = malloc(sizeof(_bitmap)); if (!image) { fprintf(stderr, "Error while allocating memory\n"); free_RLE(); fclose(ptrIn); return -1; } memset(image, 0x00, sizeof(_bitmap)); lecture = fread(image, 1, sizeof(_bitmap), ptrIn); if (lecture != sizeof(_bitmap)) { fprintf(stderr, "Error while reading data\n"); free_RLE(); fclose(ptrIn); return -1; } /* ------- */ /* Controlling the magic number and the header size */ if (image->magicNumber[0] != 'B' || image->magicNumber[1] != 'M' || image->headerSize != 40 || image->depth != 8 || image->compression != 1) { fprintf(stderr, "Error: Incompatible file type\n"); free_RLE(); fclose(ptrIn); return -1; } /* ------- */ /* Controlling the start offset */ if (image->startOffset < sizeof(_bitmap)) { fprintf(stderr, "Error: Wrong start offset\n"); free_RLE(); fclose(ptrIn); return -1; } /* ------- */ printHeader(image); /* Skipping data from the beginning to the start offset */ size_t paletteSize = image->startOffset - sizeof(_bitmap); pallet = malloc(paletteSize); if (!pallet) { fprintf(stderr, "Error while allocating memory\n"); free_RLE(); fclose(ptrIn); return -1; } // Lesen der Palette size_t bytesRead = fread(pallet, 1, paletteSize, ptrIn); if (bytesRead != paletteSize) { fprintf(stderr, "Error: Palette not completely read\n"); free_RLE(); fclose(ptrIn); return -1; } // Palette ausgeben (debugging) printPalette(pallet, paletteSize); /* RLE decompression */ data = malloc(image->width * image->height); if (!data) { fprintf(stderr, "Error while allocating memory\n"); free_RLE(); fclose(ptrIn); return -1; } printData(data, image->width * image->height); for (i = 0; total < image->imageSize; i++) { lecture = fread(&couples, 2, 1, ptrIn); if (lecture != 1) { fprintf(stderr, "Error while reading input data\n"); free_RLE(); fclose(ptrIn); return -1; } if (couples[0]) { // Standardfall: `couples[0]` gibt an, wie oft `couples[1]` wiederholt wird for (j = 0; j < couples[0]; j++) { data[total] = couples[1]; total++; } } else { // Spezialfall: `couples[0] == 0` switch (couples[1]) { case 0: // Ende der Zeile: Bewege den Zeiger zur nächsten Zeile break; case 1: // Ende des Bildes: Beenden der Dekompression fclose(ptrIn); return 1; // Erfolgreich dekodiert case 2: { // Delta-Modus: Lese zwei weitere Bytes für den Versatz uint8_t delta[2]; fread(&delta, 2, 1, ptrIn); total += delta[0] + delta[1] * image->width; break; } default: // Unkomprimierte Daten: `couples[1]` gibt die Anzahl an, lese diese Bytes lecture = fread(&data[total], 1, couples[1], ptrIn); if (lecture != couples[1]) { fprintf(stderr, "Error while reading raw input data\n"); free_RLE(); fclose(ptrIn); return -1; } total += couples[1]; // RLE-Längenbyte ist nicht nötig zu verwenden if (couples[1] & 1) { // Falls die Anzahl der Bytes ungerade ist, wird ein Padding-Byte benötigt fseek(ptrIn, 1, SEEK_CUR); } break; } } } fclose(ptrIn); return 1; } void free_RLE() { if (image) { free(image); image = NULL; } if (pallet) { free(pallet); pallet = NULL; } if (data) { free(data); data = NULL; } } uint16_t RLE_get_height(){ if (image) { return image->height; }else{ return 0; } } uint16_t RLE_get_width(){ if (image) { return image->width; }else{ return 0; } } uint32_t RLE_getDataSize(){ if (data) { return image->width * image->height; }else{ return 0; } } void RLE_get_pixel_rgb(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { uint32_t index = y * image->width + x; // Hole den Pixel-Index uint8_t colorIndex = data[index]; // Hole den Farbindex aus den Dekompressionsdaten // Finde den entsprechenden Farbwert in der Palette (4 Byte pro Eintrag) *b = pallet[colorIndex * 4]; *g = pallet[colorIndex * 4 + 1]; *r = pallet[colorIndex * 4 + 2]; *a = 255; // Im 8-Bit-BMP gibt es oft keine echte Transparenz, also standardmäßig auf 255 setzen }
In meiner Renderer Klasse wandel ich die Pixeldaten dann in 16Bit Pixel um, weil ich den Alpha Wert benötige:
backgroundPlane* Renderer::addBgPlane(string path, bool transparency) { backgroundPlane *plane = new backgroundPlane(); if(!plane) { std::cout << "Error in Bg Plane erstellung" << std::endl; return nullptr; } if(path.length() > 0) { RLEDecompression((char *)path.c_str()); unsigned char r, g, b, a; const uint16_t width = RLE_get_width(); const uint16_t height = RLE_get_height(); plane->height = height*SCALE_FACTOR; plane->width = width*SCALE_FACTOR; plane->tex_height = height; plane->tex_width = width; plane->IMG_data = new unsigned char[width*height*2]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { RLE_get_pixel_rgb(x, y, &r, &g, &b, &a); // Da BMP im BGR-Format ist, müssen Rot und Blau getauscht werden unsigned char temp = r; r = b; b = temp; // Konvertiere RGB in 5-Bit-Komponenten und 1-Bit Alpha (RGBA 1555) uint16_t r_5bit = (r >> 3) & 0x1F; // 5 MSBs von Rot uint16_t g_5bit = (g >> 3) & 0x1F; // 5 MSBs von Grün uint16_t b_5bit = (b >> 3) & 0x1F; // 5 MSBs von Blau uint16_t a_1bit = (r == 0 && g == 0 && b == 0) ? 0x0 : 0x1; // Alpha 0 für Schwarz, sonst 1 if(transparency == 0) { a_1bit = 0x1; } // Kombiniere die 1-Bit Alpha, 5-Bit Rot, 5-Bit Grün und 5-Bit Blau in einem 16-Bit-Wert uint16_t pixel = (a_1bit << 15) | (r_5bit << 10) | (g_5bit << 5) | b_5bit; // Berechnung des Ziel-Indexes im Puffer nach vertikaler Spiegelung int mirror_y = height - 1 - y; int index = (mirror_y * width + x) * 2; // 2 Bytes pro Pixel // Pixel aufteilen und in den Puffer schreiben (Little Endian) plane->IMG_data[index] = pixel & 0xFF; // LSB (niedrigstes Byte) plane->IMG_data[index + 1] = (pixel >> 8) & 0xFF; // MSB (höchstes Byte) } } free_RLE(); } bgPlanes.push_back(plane); return bgPlanes.back(); }
Ich sehe gerade keine Möglickeiten hier im Forum Anhäge ein zu fügen, deshalb habe ich das Corpus delicti auf meien Host hochgeladen (der gelbe Rahmen stamt von mir).
https://dl0rcp.darc.de/Bildschirmfoto von 2024-10-03 16-43-55_2.pngZum vergleich wie es mit 24Bit bmp Datein aus schaut:
https://dl0rcp.darc.de/Bildschirmfoto von 2024-10-03 16-45-19.pngBei genauerer betrachtung wirkt es so als sei die Textur herangezoomt.
Es muss also kein Problem mit dem RLE Alorythums perse sein.Aber warum funktiert es mit 24 Bit Bildern und mit 8bit RLE nicht?
Beim Schreiben des Beitrags ist mir noch aufgefallen, dass die Baumreihe und die grüne Wiese via VIF DMA Channel gerendert werden. Spich über die Vector Einheit der PS2.
Die andern Teturen werden über den GIF DMA Chanlel gerednert.
Trozedem sind von 5 GIF übetragungen 3 Kaputt und zwei funktieren und mit 24Bit Werten funktiert es?
Mal sehen was ihr so zu sagen habt...
VG, Denny K.
-
@D_Key sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Es muss also kein Problem mit dem RLE Alorythums perse sein.
Sehe ich genauso. RLE komprimiert ja Bereiche mit identischen Inhalt. Und auf den Bildern stimmen ja die Bereiche mit identischen Inhalt.
Aber ich würde so etwas nochmal von Hand testen. Einfach ein Screenshot machen, im jeweiligen Format speichern, was dein Programm möchte und danach das Bild mittels deinem Programm in RLE komprimiertes Bitmap wandeln.
Apropo DMA Channel. Ist das etwa Direct Memory Access? Wenn ja musst du auf die Synchronisation achten. Ein Beispiel: Der DMA liest gerade die ersten 20 Bytes aus, danach aktualisierst du die ersten 100 Bytes und danach liest der DMA die restlichen 80 Bytes, welche nun aber nicht mehr zu den ersten 20 Bytes passen.
BTW: Du solltest anfangen C++ zu lernen. Kurz und knapp, kein
new
,delete
,malloc
,free
, nutze dagegenstd::vector
,std::unique_ptr
, Zeiger sind nur in Ausnahmefällen sinnvoll,...
-
@Quiche-Lorraine
Hallo Lorraine danke erst mal für deine Antwort.
DMA ist genau das: Direct Memory Access.
Das ist aber nicht das Problem, weil DMA Transfer's habe ich nun schon einige Programmiert und bei 24Bit Bildern funktioniert ja alles.C++ brauch ich nicht zu lehren ich Programmiere seit 17 Jahren c / c++ im aber im Bereich der Signalverarbeitung,, Mikrocontroller usw.
Das PS2 SDK ist aber etwas Speziell, z.b ist der Compiler die letzte Version c++ 17 und z.B std::variant funktioniert nicht.
Ich möchte den RLE Algorithmus zur cbmp Bibliothek hinzufügen. https://github.com/mattflow/cbmp
deshalb habe ich mich klassisches C entschieden, aber nur bei dem RLE Algorithmus .
Das Spiel und die state Machine + KI ist c++
BTW: das Komplette PS2 SDK in im Klassischen C geschrieben und das hat bestimmt auch seien Grund.
https://github.com/ps2dev/ps2sdkZurück zum eigentlichen Thema.
Ich habe mal die Datei ausgeklammert und einen Bereich der Schwarz ist heraus gepickt:if(path.find("forestm3.bmp") != std::string::npos){ RLE_get_pixel_rgb(213, 18, &r, &g, &b, &a); std::cout << "r: " << unsigned(r) << " g: " << unsigned(g) << " b: " << unsigned(b) << std::endl; }
Aber schwarz ist da nichts, sondern: r: 37 g: 45 b: 15
Es liegt definitiv an dem RLE Algorithmus.Es gibt ja auf github mehre RLE Algorithmen zu finden in c/c++. aber so Richtig funktioniere die alle nicht oftmals sind Farben falsch oder einzelne Pixel sind weiß .
Ich bin was Bilder angeht nicht so bewandert was das Problem sein könnte, ich kann mich da einfach nicht rein denken.
-
@D_Key sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Es liegt definitiv an dem RLE Algorithmus.
Das ist schon mal ne nützliche Information. Hätte ja auch am Texturformat oder sowas liegen können. Zur Probe würd ich aber auch nochmal die "Plane" mit fixen Daten füttern, um zu sehen, ob da alles okay ist. Z.B. so:
void RLE_get_pixel_rgb(int x, int y, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) { *b = static_cast<unsigned char>(x * (255.0 / (image->width - 1))); *g = 0; *r = static_cast<unsigned char>(y * (255.0 / (image->height - 1))); *a = 255; }
Das sollte z.B. einen Rot/Blau-Farbverlauf über die Bilddaten erzeugen. Von Schwarz bei (0, 0) bis Magenta bei (w, h). Damit oder mit anderen sinnvollen Testdaten kann man zumindest checken ob hinter der Dekompression alles stimmt.
Und zum Algorithmus: Ist das der exakt selbe, der auch mit 24-bit funktioniert? Der sieht mir nämlich auf den ersten Blick nicht danach aus, weil der nur mit einzelnen Bytes hantiert, statt mit 3-Byte-Pixeln.
Kannst du den 24-Bit-Algorithmus auch nochmal posten? Vielleicht sieht man da ja auf Anhieb ein Problem. Im Moment fällt mir da nichts direkt auf, aber ich kenne auch das exakte Format der RLE-Bitmapdaten nicht. Daher kann ich nicht wirklich sagen, ob der Algo so korrekt ist.
C++ brauch ich nicht zu lehren ich Programmiere seit 17 Jahren c / c++ im aber im Bereich der Signalverarbeitung,, Mikrocontroller usw.
Denk trotzdem mal drüber nach, warum @Quiche-Lorraine das erwähnt hat. Der Code wirkt schon etwas "holprig" - aber das kann ja durchaus auch an schnellem Testcode zum ausprobieren liegen. Der sieht bei mir auch immer etwas gruselig aus, bevor ich ihn dann ordentlich aufgeräumt habe
-
Hallo @Finnegan,
Ich habe mal eine Foren spezifische Frage, wie kann man Zitate erstellen?
Und kann man Anhänge hinzufügen?Zum eigentlichen Thema:
Für 24 Bilder habe ich https://github.com/mattflow/cbmp genutzt
Ich bin aber schon eine Schritt weiter, aber eigentlich auch nichtIch habe DeppGPT beauftragt mir ein Python Skript zu erstellen was die Komprimierten 8Bit BMP Dateien in 24 Bit BMP Dateien umwandeln soll. Das Ergebnis war genau der selbe Matsch den ich auch bei der Playstation 2 sehe.
Ich habe drauf hin chatGPT gelöchert was das Problem sein könnte. Zwecklos, irgendwann dreht man sich im Kreis.
Es muss also was Windows BMP Spezifisches sein, was nicht allgemein bekannt ist.
Jedenfalls ist es so, dass jeder Bildbetrachter die Dateien erfolgreich öffnet und auch die 2d Grafik Bibliothek SDL interpretiert die Bilddaten korrekt.Ich habe nun über die Wayback machine eine alte libBMP gefunden die es damals für das Playstation2 Linux gab.
Jetzt kommt das verrückte. Alle Bilder die vorher korrekt dargestellt wurden sind komplett schwarz und Bilder die nicht funktionieren werden korrekt dargestellt. Also genau umgedreht.der code ist wie folgt:
```c #ifndef BITMAP_H #define BITMAP_H #include <stdbool.h> #include <stdio.h> #include <stdint.h> #include <string.h> #ifdef __cplusplus #include <cstdlib> #else #include <stdlib.h> #endif #ifdef __cplusplus extern "C" { #endif struct _bitmap_file { unsigned char bfType[2]; unsigned int bfSize; unsigned short int reserved1; unsigned short int reserved2; unsigned int bfOffs; }; struct _bitmap_info { unsigned int biSize; unsigned int biWidth; unsigned int biHeight; unsigned short int biPlanes; unsigned short int biBitCount; unsigned int biCompression; unsigned int biSizeImage; unsigned int biXPelsPerMetre; unsigned int biYPelsPerMetre; unsigned int biClrUsed; unsigned int biClrImportant; }; extern int *pixels; // Verweise auf die globalen Variablen extern int colors[256]; int read_long(FILE *in); int read_word(FILE *in); void print_bitmap_header(struct _bitmap_file *bitmap_file, struct _bitmap_info *bitmap_info); void read_bitmap_file(FILE *in, struct _bitmap_file *bitmap_file); void read_bitmap_info(FILE *in, struct _bitmap_info *bitmap_info); void raw_uncompressed(FILE *in, int width, int height, int bits, int alpha); void raw_compressed(FILE *in, int width,int height, int bits); void get_pixel_rgb_new(int index, unsigned char* r, unsigned char* g, unsigned char* b); int parse_bmp(FILE *in, uint16_t *width, uint16_t *height); #ifdef __cplusplus } #endif #endif /* BITMAP_H ``` */
#include "rlec.h" int *pixels = NULL; int colors[256]; void print_bitmap_header(struct _bitmap_file *bitmap_file, struct _bitmap_info *bitmap_info) { printf("Bitmap File Header\n"); printf("----------------------------------------------\n"); printf(" bfType: %c%c\n",bitmap_file->bfType[0],bitmap_file->bfType[1]); printf(" bfSize: %d\n",bitmap_file->bfSize); printf(" reserved1: %d\n",bitmap_file->reserved1); printf(" reserved2: %d\n",bitmap_file->reserved2); printf(" bfOffs: %d\n",bitmap_file->bfOffs); printf("----------------------------------------------\n"); printf("Bitmap Info Header\n"); printf("----------------------------------------------\n"); printf(" biSize: %d\n",bitmap_info->biSize); printf(" biWidth: %d\n",bitmap_info->biWidth); printf(" biHeight: %d\n",bitmap_info->biHeight); printf(" biPlanes: %d\n",bitmap_info->biPlanes); printf(" biBitCount: %d\n",bitmap_info->biBitCount); printf(" biCompression: %d\n",bitmap_info->biCompression); printf(" biSizeImage: %d\n",bitmap_info->biSizeImage); printf("biXPelsPerMetre: %d\n",bitmap_info->biXPelsPerMetre); printf("biYPelsPerMetre: %d\n",bitmap_info->biYPelsPerMetre); printf(" biClrUsed: %d\n",bitmap_info->biClrUsed); printf(" biClrImportant: %d\n",bitmap_info->biClrImportant); printf("----------------------------------------------\n"); } int read_word(FILE *in) { int c; c=getc(in); c=c|(getc(in)<<8); return c; } int read_long(FILE *in) { int c; c=getc(in); c=c|(getc(in)<<8); c=c|(getc(in)<<16); c=c|(getc(in)<<24); return c; } void read_bitmap_file(FILE *in, struct _bitmap_file *bitmap_file) { bitmap_file->bfType[0]=getc(in); bitmap_file->bfType[1]=getc(in); bitmap_file->bfSize=read_long(in); bitmap_file->reserved1=read_word(in); bitmap_file->reserved2=read_word(in); bitmap_file->bfOffs=read_long(in); } void read_bitmap_info(FILE *in, struct _bitmap_info *bitmap_info) { bitmap_info->biSize=read_long(in); bitmap_info->biWidth=read_long(in); bitmap_info->biHeight=read_long(in); bitmap_info->biPlanes=read_word(in); bitmap_info->biBitCount=read_word(in); bitmap_info->biCompression=read_long(in); bitmap_info->biSizeImage=read_long(in); bitmap_info->biXPelsPerMetre=read_long(in); bitmap_info->biYPelsPerMetre=read_long(in); bitmap_info->biClrUsed=read_long(in); bitmap_info->biClrImportant=read_long(in); } void raw_uncompressed(FILE *in, int width, int height, int bits, int alpha) { int x,y; int c=0,t; int byte_count; for (y=height-1; y>=0; y--) { byte_count=0; for (x=0; x<width; x++) { if (bits==8 || bits==24 || bits==32) { if (bits==8) { c=getc(in); c=colors[c]; byte_count++; } else if (bits==24) { c=getc(in)+(getc(in)<<8)+(getc(in)<<16); byte_count=byte_count+3; } else if (bits==32) { c=getc(in)+(getc(in)<<8)+(getc(in)<<16); t=getc(in); if (t==255 && alpha ==-2) alpha = c; byte_count=byte_count+4; } pixels[x+(y*width)]=c; } else if (bits==4) { c=getc(in); byte_count++; pixels[x+(y*width)]=colors[((c>>4)&15)]; x++; if (x<width) { pixels[x+(y*width)]=colors[(c&15)]; } } else if (bits==1) { c=getc(in); byte_count++; for (t=7; t>=0; t--) { if (x<width) { if (((c>>t)&1)==0) { pixels[x+(y*width)]=colors[0]; } else { pixels[x+(y*width)]=colors[1]; } } x++; } x=x-1; } } c=(byte_count%4); if (c!=0) { for (t=c; t<4; t++) { getc(in); } } } } void raw_compressed(FILE *in, int width,int height, int bits) { int x,y; int c,t,r; y= height-1; x=0; while (1) { c=getc(in); if (c==EOF) return; if (c!=0) { r=getc(in); for (t=0; t<c; t++) { if (bits==4) { if ((t%2)==0) { pixels[x+(y*width)]=colors[(r>>4)]; } else { pixels[x+(y*width)]=colors[(r&15)]; } } else if (bits==8) { pixels[x+(y*width)]=colors[r]; /* printf("Pixel_1: %d \n", pixels[x+(y*width)]); if(x+(y*width) == 21687){ printf("Pixel_100_1: %d \n", pixels[x+(y*width)]); } */ } x++; } } else { r=getc(in); if (r==0) { x=0; y--; continue; } else if (r==1) { break; } else if (r==2) { x=x+getc(in); y=y-getc(in); return; } for (t=0; t<r; t++) { c=getc(in); if (bits==8) { pixels[x+(y*width)]=colors[c]; /* printf("Pixel_2: %d \n", pixels[x+(y*width)]); if(x+(y*width) == 21828){ printf("Pixel_100_2: %d \n", pixels[x+(y*width)]); } */ } else if (bits==4) { pixels[x+(y*width)]=colors[c>>4]; t++; if (t<r) { x++; pixels[x+(y*width)]=colors[(c&15)]; } } x++; } if (bits==8) { c=r%2; } else if (bits==4) { t=(r/2)+(r%2); c=t%2; } if (c!=0) { getc(in); } } } } int parse_bmp(FILE *in, uint16_t *width, uint16_t *height) { struct _bitmap_file bitmap_file; struct _bitmap_info bitmap_info; int t; memset(&bitmap_file, 0, sizeof(struct _bitmap_file)); memset(&bitmap_info, 0, sizeof(struct _bitmap_info)); memset(colors, 0, 256 * sizeof(int)); read_bitmap_file(in, &bitmap_file); if (bitmap_file.bfType[0] != 'B' || bitmap_file.bfType[1] != 'M') { printf("Not a bitmap.\n"); return -1; } read_bitmap_info(in, &bitmap_info); print_bitmap_header(&bitmap_file, &bitmap_info); colors[0] = 0; colors[1] = 0xffffff; colors[255] = 0xffffff; if (bitmap_info.biClrImportant == 0 && bitmap_info.biBitCount == 8) { bitmap_info.biClrImportant = 256; } for (t = 0; t < bitmap_info.biClrImportant; t++) { colors[t] = read_long(in); } *width = bitmap_info.biWidth; *height = bitmap_info.biHeight; pixels = malloc((*width) * (*height) * sizeof(int)); memset(pixels, 0,(*width) * (*height) * sizeof(int)); fseek(in, bitmap_file.bfOffs, 0); if (bitmap_info.biCompression == 0) { raw_uncompressed(in, *width, *height, bitmap_info.biBitCount, -2); } else if (bitmap_info.biCompression == 1) { raw_compressed(in, *width, *height, 8); /*printf("Pixel_COMP_1: %d \n", pixels[21687]);*/ /*rintf("Pixel_COMP_2: %d \n", pixels[21828]);*/ } else if (bitmap_info.biCompression == 2) { raw_compressed(in, *width, *height, 4); } else if (bitmap_info.biCompression == 3) { raw_uncompressed(in, *width, *height, bitmap_info.biBitCount, -2); } else { printf("This type of compression is not supported at this time.\n"); return 0; } return 0; } void get_pixel_rgb_new(int index, unsigned char* r, unsigned char* g, unsigned char* b) { int pixel = pixels[index]; /* if(index == 21687 ){ printf("GET Pixel_COMP_1: %d \n", pixel); printf("GET Pixel_COMP_2: %d \n", pixel); } */ // Extract the RGB components from the 32-bit int *r = (pixel >> 16) & 0xFF; // Red is in bits 16-23 *g = (pixel >> 8) & 0xFF; // Green is in bits 8-15 *b = pixel & 0xFF; // Blue is in bits 0-7 }
in meiner render Klasse habe auch aufgeräumt und die Roh Daten nicht in unsigend char gespeichert sondern in unint16_t,
Das ist etwas übersichlticher.backgroundPlane* Renderer::addBgPlane(string path, bool transparency) { //if(path.find("land4") != std::string::npos ){ backgroundPlane *plane = new backgroundPlane(); if(!plane) { std::cout << "Error in Bg Plane erstellung" << std::endl; return nullptr; } if(path.length() > 0) { unsigned char r, g, b; uint16_t width, height; FILE *in=fopen(path.c_str(),"rb"); if (!in) { printf("Could not open bmp file for reading."); return nullptr; } parse_bmp(in, &width, &height); fclose(in); plane->height = (float)height*SCALE_FACTOR; plane->width = (float)width*SCALE_FACTOR; plane->tex_height = height; plane->tex_width = width; plane->IMG_data = new uint16_t[width * height]; // 2 Bytes pro Pixel for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int pixel_index = y * width + x; get_pixel_rgb_new(pixel_index, &r, &g, &b); if(path.find("land4") != std::string::npos)std::cout << "r: " << unsigned(r) << " g: " << unsigned(g) << "b: " << unsigned(b) << std::endl; // Da BMP im BGR-Format ist, müssen Rot und Blau getauscht werden unsigned char temp = r; r = b; b = temp; // Konvertiere RGB in 5-Bit-Komponenten und 1-Bit Alpha (RGBA 1555) uint16_t r_5bit = (r >> 3) & 0x1F; // 5 MSBs von Rot uint16_t g_5bit = (g >> 3) & 0x1F; // 5 MSBs von Grün uint16_t b_5bit = (b >> 3) & 0x1F; // 5 MSBs von Blau uint16_t a_1bit = (r == 0 && g == 0 && b == 0) ? 0x0 : 0x1; // Alpha 0 für Schwarz, sonst 1 if(transparency == 0) { a_1bit = 0x1; } // Kombiniere die 1-Bit Alpha, 5-Bit Rot, 5-Bit Grün und 5-Bit Blau in einem 16-Bit-Wert uint16_t pixel = (a_1bit << 15) | (r_5bit << 10) | (g_5bit << 5) | b_5bit; if(pixel_index == 200)std::cout << "pixel 16: " << unsigned(pixel) << std::endl; plane->IMG_data[y * width + x] = pixel; } } free(pixels); } bgPlanes.push_back(plane); return bgPlanes.back(); }
Die Cout Ausgabe:
if(path.find("land4") != std::string::npos)std::cout << "r: " << unsigned(r) << " g: " << unsigned(g) << "b: " << unsigned(b) << std::endl;gibt wie erwartet bei rgb 0 zurück, aber warum?
Vor allem, die Texturen des Ursprünglichen Spiels sind ja nun nicht mit verscheiden Editoren erstellt worden.
Warum sind dann die bmp Datein trozedem unterschiedich, und vor allem wo, was ist der unterschied.PS: Unstrukturierter Code entsteht bei mir meistens wenn ich anfange Fehler zu suchen und permante Dinge auskomentiere oder print Ausgaben einfüge.
Die PS2 ist zudem etwas soderbar, da sich der Code aus c, c++ und VU Assabler + MIPS R5900 Assabmler zusammensetzt. Zusätlich kommt noch der C bzw MIPS R3000A Assambler Code vom IOP dazu.
Für das Makefile habe ich eien Woche benötigt ehe alles lief
-
@D_Key sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Es muss also was Windows BMP Spezifisches sein, was nicht allgemein bekannt ist.
C++ brauch ich nicht zu lehren ich Programmiere seit 17 Jahren c / c++ im aber im Bereich der Signalverarbeitung,, Mikrocontroller usw.
Uff...
Dafür dass du offiziell seit 17 Jahren im Bereich C/C++ im Embedded Bereich tätig bist, zeigst du deutliche Wissenlücken.
- Gerade im Embedded Bereich ist doch Dokumentation essentiell wichtig. Hardware ist stellenweise recht zickig und ohne Doku ist man da aufgeschmissen.
- C/C++ ist hoffnungslos veraltet und wird durch die neuere Standards ersetzt. Und die neueren Standards stellen aus meiner SIcht neue Sprachen dar. Oder programmiere doch mal folgendes in C/C++ nach:
int x = 0; std::mutex m; int a[] = {1, 2}; std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int) { std::lock_guard<std::mutex> guard(m); // Error: lock_guard constructor calls m.lock() ++x; }
Quelle: https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag_t
- Lies dich bitte mal bezüglich RAII, Rule of five ein.
- Sorry, aber ich mag keine Zeiger mehr, da diese viele Seiteneffekte haben. Ehrlich gesagt genügen mir die vielen Seiteneffekte im Embedded Bereich.
Also komm in die Pötte und zerlege endlich das Problem:
- Teile dein Programm in eine RLE Konvertierung und Anzeige auf.
- Baue eine kleine Testreihe für deine RLE Konvertierung auf,
- Schnappe dir die Dokumentation bezüglich RLE Konvertierung und pfeife sie dir rein. Das dürfte ja aufgrund deiner Erfahrungen im Embedded Bereich nicht unbekannt sein.
- Schnappe dir ein Beispiel und wandele diese mit GIMP in RLE. Vergleiche dein Ergebnis mit Gimp.
- Schnappe dir Python und generiere eine Reihe von Bildern, in dem du das Beispiel z.B. immer um ein Pixel verschiebst
- Fütttere damit deine Video-Pipeline und prüfe ob damit deine Video-Ausgabe.
- Funktioniert das auch mit unterschiedlichen Timings?
BTW:
Sorry, wenn ich etwas gefrustet klinge. Aber ich entwickele gerade Firmware für Nordic Chips. Das SDK ist mangelhaft, die Hardware recht zickig und ich erlebe gerade wie empfindlich ein Stück zertifizierte Software (Softdevice) auf einen nicht vorhandenen XTAL reagiert, oder wie man von einer Menge von defines erschlagen wird
-
@Quiche-Lorraine sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Sorry, wenn ich etwas gefrustet klinge. Aber ich entwickele gerade Firmware für Nordic Chips.
Hi, also habe die Zitate Funktion gefundene
Ja also, ich kenne das Problem nur zu gut, mit dem schlecht Dokumentierten SDK's.
Oder auch mit Fehlern im Chip, die nur unter ganz bestimmt Umständen auftreten.Ich hatte mich mal vor Jahren mit NXP angelegt bei deren Kinetis IC's.
Da hatte sich das ADC Eingassignal mit der ADC PLL vermischt, aber nur dann wenn man es mit dem Inneren ADC Amp bis ins ins Rechteck verstärkt hat und die Eingangsfrequenz 25kHz betrug.
Also Eingang Sinus -> Verstärkt bis es Rechteckig wird.
Das Rechteck hat dann derartige Oberwellen verursacht, das ein Teil des ADC Eingang Signals zum DAC wider bei 300Hz wider heraus kam, was für derartiges "Gezwitscher "gesorgt hat. Furchtbar war das.
Das Eingangssignal war ein FM Singsang mit 25khz Trägerfrequenz, daher das Gezwitscher.Im Enddefekt half nur das FM Signal auf eine andere Frequenz zu mischen.
Zurück zum Thema.
Ich habe das Problem gefunden. Ich habe den Code weiter zerstückelt und geschaut, wo entstehen die Nullen.
Vor allem bei einem Bild was überhaupt kein Schwarz enthält.
Problem war hier das return, was ich durch ein continue ersetzt habe :else if (r==2) { x=x+getc(in); y=y-getc(in); continue;//return; }
dann habe ich noch das Tauschen der Farben:
unsigned char temp = r; r = b; b = temp;
durch std::swap(r, b); ersetzt.
PS:
std::shared_ptr oder std::unique_ptr sind bei der Playstation 2 nur bedingt gut.
auch std::vector hat so seine Macken, man kann zwar mit reserve(), verhindern das der Speicher häufig um sortiert wird, aber auch so ist std::vector schon eine Bremse auf der PS2.
Ich hatte zuerst ein std::vector mit std::varaint. Bei nur 100 Charaktern hatte ich schon Frame drop ohne Ende.
Ja und 200 Charaktere gibt es zu spitzen Zeiten auf der Map.Also dynamische Speicher Verwaltung auf der PS2 sollte man behutsam einsetzen, weil der DRAM einfach Grotten lahm ist, alles auf der PS2 ist lahm.
-
@D_Key Wenn dynamische Speicherverwaltung problematisch ist, könntest du dir pmr Allokatoren anschauen. Damit kannst du einige c++ Container ohne Heap Allokationen verwenden.
-
Bzgl. dem Vertauschen von
r
undb
, kannst du doch einfach die Variablen tauschen:get_pixel_rgb_new(pixel_index, &b, &g, &r); // swap r & b
-
@D_Key sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Ich hatte zuerst ein std::vector mit std::varaint. Bei nur 100 Charaktern hatte ich schon Frame drop ohne Ende.
Zwei kleinen Sachen springen mir diesbezüglich ins Auge.
backgroundPlane* Renderer::addBgPlane(string path, bool transparency)
Der erste Punkt ist die Rückgabe eines allokierten Speichers. Wer gibt diesen frei?
Der zweite Punkt betrifft die Übergabe des Parameters
path
. Je nach Compiler-Stand, C++ Standard, Aufruf kostet dich dieser Aufruf eine Kopie vonpath
. Warum übergibst du diesen nicht mittels konstanter Referenz?
-
@D_Key sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Also dynamische Speicher Verwaltung auf der PS2 sollte man behutsam einsetzen, weil der DRAM einfach Grotten lahm ist, alles auf der PS2 ist lahm.
Inwiefern macht das Sinn? Liegen Stack und Heap in unterschiedlichen Hardwarespeichern? Also liegen Programmcode und Stack in DRAM und der Heap in Flashspeicher oder Ähnlichem? Kann ich iwie nicht glauben.
-
@D_Key sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
...
C++ brauch ich nicht zu lehren ich Programmiere seit 17 Jahren c / c++ im aber im Bereich der Signalverarbeitung,, Mikrocontroller usw.
...Ich glaube, du meinst "lernen" statt "lehren", oder? Wenn das der Fall ist, hast du ein massives Problem. In dem Moment, wo man aufhört, sich moderne Techniken aneignen oder generell dazulernen zu wollen, weil man glaubt, dass man eh schon alles kann, wird man schlechter.
Dein Code ist ein wilder Mix aus C und C++, du solltest dich für eins von beiden entscheiden. Wenn du fit in C bist, dann mach C, wenn du C++ lernen willst, dann mach C++. Aber nicht das, was du hier zeigst.Statt alles selbst zu programmieren solltest du mal einen Blick auf fertige Bibliotheken werfen, z.B. CImg.
Ansonsten stimme ich @Quiche-Lorraine in all seinen Kritipunkten zu.
-
@D_Key sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Ich hatte zuerst ein std::vector mit std::varaint. Bei nur 100 Charaktern hatte ich schon Frame drop ohne Ende.
Ja und 200 Charaktere gibt es zu spitzen Zeiten auf der Map.Wenn du Vektoren genauso in Funktionsaufrufen benutzt, wie du
std::string
benutzt, dann wundert mich das nicht.
Bitte lies dich in die verschiedenen Möglichkeiten ein, wie Parameter an Funktionen übergeben werden (call-by-value und call-by-(const-)reference).
-
Uii, das ist sind auf einmal viele Leute aufgewacht.
@Th69 sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Bzgl. dem Vertauschen von r und b, kannst du doch einfach die Variablen tauschen:
Jo, stimmt^^ das ist natürlich noch kürzer.
@Quiche-Lorraine sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Der erste Punkt ist die Rückgabe eines allokierten Speichers. Wer gibt diesen frei?
Der zweite Punkt betrifft die Übergabe des Parameters path.Für die Speicherfreigabe habe eine separate Funktion. Der Hintergrund wird nur gelöscht bei verlassen des Levels oder beim verlassen des Spiels.
Den String über habe ich am Sonntag Abend schon auf eine Zeiger geändert.
Ich musste weitere Parameter an die adBgPlane Funktion übergeben, da habe ich das gleich geändert.@Schlangenmensch sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
@D_Key Wenn dynamische Speicherverwaltung problematisch ist, könntest du dir pmr Allokatoren anschauen. Damit kannst du einige c++ Container ohne Heap Allokationen verwenden.
Das klingt nach eine prima Idee, wenn das mit dem PS2 SDK funktioniert mache ich das.
@DocShoe sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Wenn das der Fall ist, hast du ein massives Problem. In dem Moment, wo man aufhört, sich moderne Techniken aneignen oder generell dazulernen zu wollen, weil man glaubt, dass man eh schon alles kann, wird man schlechter.
Dein Code ist ein wilder Mix aus C und C++,Der wilde Mix ist jetzt daher geschuldet, das ich mich eigentlich ich gar nicht mit dem bmp Dateiformat auseinander setzen wollte. Für mich hat cbmp von github funktioniert. Bis ich bemerke habe das die Originalen Textur Altlas'se 8Bit RLE Komprimiert sind.
Klassisches C mag ich überhaupt nicht mehr, weil keine Objektorientierung.
Immer nur neuen Standards zu folgen halte ich für Überreiben. Nicht Immer ist das neuste auch immer gut.@DocShoe sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Liegen Stack und Heap in unterschiedlichen Hardwarespeichern? Also liegen Programmcode und Stack in DRAM und der Heap in Flashspeicher oder Ähnlichem? Kann ich iwie nicht glauben.
Das ist eine sehr interessante Frage. Also Heap und Stack liegen Im DRAM.
Programmcode hat einen eignen Speicher auf der CPU. Zudem hat die EE zwei Vector Einheiten, die einen eignen Speicherbereich haben (MicroMemory,) wo der VU Assembler landet.
Ich weiß auch Atok nicht wo Konstanten hin gespeichert werden. Flash Speicher gab es bei der Playstation 2 nicht.
Es gibt noch eine "Section .data" für große arrays, da es aber kein Flash Speicher gibt vermute ich, das jedes mal das CD Laufwerk bei einem Zugriff auf ein solches Array loslegen muss. Für den IOP also den PS1 Prozessor gibt es noch einen 2 MB EDO-RAM.
Zudem gibt es noch einen schnellen 16kB scratchpad RAM.@DocShoe sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Wenn du Vektoren genauso in Funktionsaufrufen benutzt, wie du std::string benutzt, dann wundert mich das nicht.
Nein, ich habe Zeiger im Variant abgelegt. Ich bin aber allgemein nicht zufrieden mit dem Variant, weil ich eine strikte Reihenfolge einhalten muss wie meine Gameobjekte von der gameloop durchlaufen werden müssen. Zuerst Charakter, dann Waffen, dann Zauber-angriffe usw. Wahrscheinlich muss Reihenfolge nicht einhalten aber für mich zum debuggen ist es erst mal das einfachste.
Ich habe jetzt verschiedene Vectoren also mit verscheiden Klassen.Neben bei ist mir aufgefallen unter Windoof 11 lassen sich die BMP Dateien auch nicht öffnen im Standard Bildbetrachter.
Da kommt auch nur Matsch heraus. In Ubuntu klappt das.
Da die BMP Dateien auch 20 Jahre alt sind macht es den anschien als hat sich der RLE Algorithmus mal geändert.
-
@D_Key sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Nein, ich habe Zeiger im Variant abgelegt.
Warum das denn?
Mich würde da mal den Code interresieren.
-
@Quiche-Lorraine sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Warum das denn?
Das weiß ich nicht mehre genau, weshalb ich das gemacht habe.
Ich komme ja nicht aus der Spielteewicklung das ist eine andere Abstraktionsebene als DSP.
Anfangs bin ich ich ziemlich im Dunkeln getappt, weil ich die Objektorientierung bzw Vererbung nicht hin bekomme habe.
Z.b gibt es Charaktere , Freeze, Firen, Bandit usw.. Da dachte ich, klar machst alt genauso so die einzelnen Klassen.
Bin dann aber dahinter gekommen, dass wird Murks, weil jeder Freeze, Firen, Bandit ist ein Charakter.
Class Charakter erbt von class LivingObject. Wobei LivingObject die Volumenbereiche bereitstellt und auch die Positionen im Textur-atlas angibt. LivingObject ist die Basis Klasse für alle GameObjecte.Das zumindest was die C++ Problematik an geht. Die PS2 hat mich dann noch mal ganz anders gef***...
Das Makefile für den ganze code schreiben ..eine Geburt
Der Vektor Assembler war anfangs furchtbar.
Die Alpha blending Einstellung um das Schwarz heraus zu rechen, bin bald ausgerastet.Und neben bei, ich habe ich mal Serversteiges Programmierern gelernt ... PHP, Perl, Java und JavaScript.
Durch ein Hobby Bastler-Treffen bin ich eher unfreiwillig in die Mikrocontroller Programmierung gerutscht.
Die DSP Kenntnisse hat ich schon von anfang an, weil ich sehr viel mit Audio Streaming und Resampling bzw Audio Kompression zu tun hatte. Durch die DSP Vorkenntnisse bin ich erst mit den Jungs da in Verbindung getreten.@Quiche-Lorraine sagte in 8-Bit RLE Bitmap wird nicht richtig geladen.:
Mich würde da mal den Code interresieren.
Sorry aber nee, ich habe den Variant jetzt verbannt. Zudem Starte ich meinn Programmier PC heute nicht mehr.
Mich würde viele mehr interessiere ob hardwarespezifische Frage zum Rendern auf der PS2 stellen kann?
z.B beeinflusst das Z-Bufferign mein Alpha Blending, Ich kann mich hinter Transparenten Flächen verstecken (wozu ist die Fläche den transparent).
Oder aber hätte ich gerne einen Framebuffer von 800x600 groß ist und ein Screen Config von 1280 zu 720 sprich 720p.
Wenn ich das mache ist das Bild nach unten Rechts verschoben es muss aber Technisch möglich sein, da der kleinerer Framebuffer auf das ganzen Fernseher "gezogen" wird.