/** * schreibt die Bilddaten in eine Datei. * * @param[in] file Dateihandle der Datei * @param[in] palette Grundpalette * * @return liefert Null bei Erfolg, ungleich Null bei Fehler * * @author FloSoft */ int libsiedler2::baseArchivItem_Bitmap_Shadow::write(FILE *file, const ArchivItem_Palette *palette) const { unsigned char *data = NULL; if(file == NULL) return 1; if(palette == NULL) palette = this->palette; if(palette == NULL) return 2; if(width == 0 || height == 0) return 2; // Nullpunkt X schreiben if(libendian::le_write_s(nx, file) != 0) return 3; // Nullpunkt Y schreiben if(libendian::le_write_s(ny, file) != 0) return 4; // Unbekannte Daten schreiben char unknown[4] = {0x00, 0x00, 0x00, 0x00}; if(libendian::le_write_c(unknown, 4, file) != 4) return 5; // Breite schreiben if(libendian::le_write_us(width, file) != 0) return 6; // Höhe einlesen if(libendian::le_write_us(height, file) != 0) return 7; // Unbekannte Daten schreiben char unknown2[2] = {0x01, 0x00}; if(libendian::le_write_c(unknown2, 2, file) != 2) return 8; // maximale größe von RLE: width*height*2 data = new unsigned char[height*4+width*height*2]; memset(data, 0, width*height*2); // Startadressen unsigned char *image = &data[height*2]; unsigned short *starts = (unsigned short*)&data[0]; // Schattendaten kodieren unsigned short position = 0; for(unsigned short y = 0; y < height; ++y) { unsigned short x = 0; // Startadresse setzen starts[y] = position + height*2; // Solange Zeile nicht voll while(x < width) { // graue Pixel schreiben unsigned char count, color; for(count = 0; count < width-x; ++count) { color = tex_getPixel(x+count, y, palette); if(color == TRANSPARENT_INDEX) break; } image[position++] = count; x += count; // transparente Pixel schreiben for(count = 0; count < width-x; ++count) { color = tex_getPixel(x+count, y, palette); if(color != TRANSPARENT_INDEX) break; } image[position++] = count; x += count; } image[position++] = 0xFF; } image[position++] = 0xFF; unsigned int length = position + height*2; // Länge schreiben if(libendian::le_write_ui(length, file) != 0) return 9; // Daten schreiben for(unsigned int i = 0; i < height; ++i) { if(libendian::le_write_us(((unsigned short *)data)[i], file) != 0) return 10; } if(libendian::le_write_uc(&data[height*2], length-(height*2), file) != (int)(length-(height*2))) return 11; delete[] data; return 0; }
/** * schreibt das Bitmap in einen Puffer. * * @param[in,out] buffer Zielpuffer * @param[in] buffer_width Breite des Puffers * @param[in] buffer_height Höhe des Puffers * @param[in] buffer_format Texturformat des Puffers * @param[in] palette Grundpalette * @param[in] to_x Ziel-X-Koordinate * @param[in] to_y Ziel-Y-Koordinate * @param[in] from_x Quell-X-Koordinate * @param[in] from_y Quell-Y-Koordinate * @param[in] from_w zu kopierende Breite * @param[in] from_h zu kopierende Höhe * * @return Null falls Bitmap in Puffer geschrieben worden ist, ungleich Null bei Fehler * * @author FloSoft */ int libsiedler2::baseArchivItem_Bitmap::print(unsigned char* buffer, unsigned short buffer_width, unsigned short buffer_height, TEXTURFORMAT buffer_format, const ArchivItem_Palette* palette, unsigned short to_x, unsigned short to_y, unsigned short from_x, unsigned short from_y, unsigned short from_w, unsigned short from_h) const { if(buffer == NULL || buffer_width == 0 || buffer_height == 0) return 1; if(palette == NULL) palette = this->palette; if(palette == NULL) return 2; if(from_w == 0 || from_x + from_w > tex_width) from_w = tex_width - from_x; if(from_h == 0 || from_y + from_h > tex_height) from_h = tex_height - from_y; unsigned short bpp; switch(buffer_format) { case FORMAT_RGBA: bpp = 4; break; case FORMAT_PALETTED: bpp = 1; break; default: bpp = 0; break; } for(unsigned short y = from_y, y2 = to_y; y2 < buffer_height && y < from_y + from_h; ++y, ++y2) { for(unsigned short x = from_x, x2 = to_x; x2 < buffer_width && x < from_x + from_w; ++x, ++x2) { unsigned int position = (y2 * buffer_width + x2) * bpp; unsigned int position2 = (y * tex_width + x) * tex_bpp; switch(tex_bpp) { case 1: // Textur ist Paletted { switch(bpp) { case 1: { // Ziel ist auch Paletted if(tex_data[position2] != TRANSPARENT_INDEX) // bei Transparenz wird buffer nicht verändert buffer[position] = tex_data[position2]; } break; case 4: { // Ziel ist RGB+A if(tex_data[position2] != TRANSPARENT_INDEX) // bei Transparenz wird buffer nicht verändert { palette->get(tex_data[position2], buffer[position + 2], buffer[position + 1], buffer[position + 0]); buffer[position + 3] = 0xFF; } } break; } } break; case 4: // Textur ist RGBA { switch(bpp) { case 1: { // Ziel ist Paletted if(tex_data[position2] != TRANSPARENT_INDEX) // bei Transparenz wird buffer nicht verändert buffer[position] = tex_getPixel(x, y, palette); } break; case 4: { // Ziel ist auch RGB+A if(tex_data[position2 + 3] == 0xFF) // bei Transparenz wird buffer nicht verändert { buffer[position + 0] = tex_data[position2 + 0]; // b buffer[position + 1] = tex_data[position2 + 1]; // g buffer[position + 2] = tex_data[position2 + 2]; // r buffer[position + 3] = tex_data[position2 + 3]; // a } } break; } } break; } } } // Alles ok return 0; }
/** * schreibt die Bilddaten in eine Datei. * * @param[in] file Dateihandle der Datei * @param[in] palette Grundpalette * * @return liefert Null bei Erfolg, ungleich Null bei Fehler * * @bug Bei zu großen Bilddaten gibts einen Überlauf der Zeilenstartadressen, * im Moment wird dann der Zeilenstart auf 0xFFFF gesetzt. */ int libsiedler2::baseArchivItem_Bitmap_RLE::write(std::ostream& file, const ArchivItem_Palette* palette) const { if(!file) return 1; if(palette == NULL) palette = this->palette_; if(palette == NULL) return 2; if(width_ == 0 || height_ == 0) return 2; libendian::LittleEndianOStreamRef fs(file); // Nullpunkt X schreiben fs << nx_; // Nullpunkt Y schreiben fs << ny_; // Unbekannte Daten schreiben char unknown[4] = {0x00, 0x00, 0x00, 0x00}; fs.write(unknown, sizeof(unknown)); // Breite schreiben fs << width_; // Höhe einlesen fs << height_; // Unbekannte Daten schreiben char unknown2[2] = {0x01, 0x00}; fs.write(unknown2, sizeof(unknown2)); // maximale größe von RLE: width*height*2 std::vector<unsigned char> image(width_ * height_ * 2); // Startadressen std::vector<unsigned short> starts(height_); // RLE kodieren unsigned int position = 0; for(unsigned short y = 0; y < height_; ++y) { unsigned short x = 0; // Startadresse setzen if((unsigned short)(position + height_ * 2) < (position + height_ * 2)) starts[y] = 0xFFFF; else starts[y] = (unsigned short)(position + height_ * 2); // Solange Zeile nicht voll while(x < width_) { unsigned short count; unsigned char color; // farbige Pixel schreiben for(count = 0; count < width_ - x; ++count) { color = tex_getPixel(x + count, y, palette); if(color == TRANSPARENT_INDEX) break; image[position + 1 + count] = color; if(count == 0x7F) break; } image[position] = (unsigned char)count; position += 1 + count; x += count; // transparente Pixel schreiben for(count = 0; count < width_ - x; ++count) { color = tex_getPixel(x + count, y, palette); if(color != TRANSPARENT_INDEX || count == 0xFF) break; } image[position++] = (unsigned char)count; x += count; } image[position++] = 0xFF; } image[position++] = 0xFF; unsigned int length = position + height_ * 2; // Länge schreiben fs << length; // Daten schreiben fs << starts << image; return 0; }