/**
 *  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;
}
Exemple #3
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;
}