|
|
1febca |
/* === S Y N F I G ========================================================= */
|
|
|
1febca |
/*! \file synfig/rendering/software/function/packedsurface.cpp
|
|
|
1febca |
** \brief PackedSurface
|
|
|
1febca |
**
|
|
|
1febca |
** $Id$
|
|
|
1febca |
**
|
|
|
1febca |
** \legal
|
|
|
1febca |
** ......... ... 2016 Ivan Mahonin
|
|
|
1febca |
**
|
|
|
1febca |
** This package is free software; you can redistribute it and/or
|
|
|
1febca |
** modify it under the terms of the GNU General Public License as
|
|
|
1febca |
** published by the Free Software Foundation; either version 2 of
|
|
|
1febca |
** the License, or (at your option) any later version.
|
|
|
1febca |
**
|
|
|
1febca |
** This package is distributed in the hope that it will be useful,
|
|
|
1febca |
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
1febca |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
1febca |
** General Public License for more details.
|
|
|
1febca |
** \endlegal
|
|
|
1febca |
*/
|
|
|
1febca |
/* ========================================================================= */
|
|
|
1febca |
|
|
|
1febca |
/* === H E A D E R S ======================================================= */
|
|
|
1febca |
|
|
|
1febca |
#ifdef USING_PCH
|
|
|
1febca |
# include "pch.h"
|
|
|
1febca |
#else
|
|
|
1febca |
#ifdef HAVE_CONFIG_H
|
|
|
1febca |
# include <config.h></config.h>
|
|
|
1febca |
#endif
|
|
|
1febca |
|
|
|
2b738b |
#include <cstdlib></cstdlib>
|
|
|
1febca |
#include <cstring></cstring>
|
|
|
1febca |
|
|
|
1febca |
#include <vector></vector>
|
|
|
1febca |
#include <map></map>
|
|
|
1febca |
|
|
|
1febca |
#include "packedsurface.h"
|
|
|
1febca |
|
|
|
1febca |
#include <synfig real.h=""></synfig>
|
|
|
1febca |
#include <synfig zstreambuf.h=""></synfig>
|
|
|
1febca |
|
|
|
1febca |
#endif
|
|
|
1febca |
|
|
|
1febca |
using namespace synfig;
|
|
|
1febca |
using namespace rendering;
|
|
|
1febca |
using namespace software;
|
|
|
1febca |
|
|
|
1febca |
/* === M A C R O S ========================================================= */
|
|
|
1febca |
|
|
|
1febca |
/* === G L O B A L S ======================================================= */
|
|
|
1febca |
|
|
|
1febca |
/* === P R O C E D U R E S ================================================= */
|
|
|
1febca |
|
|
|
1febca |
/* === M E T H O D S ======================================================= */
|
|
|
1febca |
|
|
|
1febca |
|
|
|
1febca |
PackedSurface::Reader::Reader():
|
|
|
1febca |
surface(NULL),
|
|
|
1febca |
first(NULL),
|
|
|
1febca |
last(NULL),
|
|
|
1febca |
cache(NULL)
|
|
|
1febca |
{ }
|
|
|
1febca |
|
|
|
1febca |
PackedSurface::Reader::Reader(const PackedSurface &surface):
|
|
|
1febca |
surface(NULL),
|
|
|
1febca |
first(NULL),
|
|
|
1febca |
last(NULL),
|
|
|
1febca |
cache(NULL)
|
|
|
1febca |
{
|
|
|
1febca |
open(surface);
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
PackedSurface::Reader::~Reader()
|
|
|
1febca |
{
|
|
|
1febca |
close();
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
void
|
|
|
1febca |
PackedSurface::Reader::open(const PackedSurface &surface)
|
|
|
1febca |
{
|
|
|
1febca |
if (this->surface == &surface)
|
|
|
1febca |
return;
|
|
|
1febca |
|
|
|
1febca |
close();
|
|
|
1febca |
|
|
|
1febca |
if (surface.width <= 0 && surface.height <= 0)
|
|
|
1febca |
return;
|
|
|
1febca |
|
|
|
1febca |
{
|
|
|
1febca |
this->surface = &surface;
|
|
Rodolfo Ribeiro Gomes |
cfe072 |
std::lock_guard<std::mutex> lock(surface.mutex);</std::mutex>
|
|
|
1febca |
surface.readers.insert(this);
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
if (surface.chunk_size)
|
|
|
1febca |
{
|
|
|
1febca |
chunks.resize(surface.chunks_width*surface.chunks_height, NULL);
|
|
|
1febca |
|
|
|
1febca |
int cacheCount = std::max(surface.chunks_width, surface.chunks_height)*CacheRows;
|
|
|
1febca |
assert(cacheCount > 1);
|
|
|
1febca |
int cacheEntrySize = sizeof(CacheEntry) + surface.chunk_size;
|
|
|
1febca |
cache = new char[cacheCount*cacheEntrySize];
|
|
|
1febca |
first = (CacheEntry*)cache;
|
|
|
1febca |
for(int i = 0; i < cacheCount; ++i)
|
|
|
1febca |
{
|
|
|
1febca |
CacheEntry *entry = (CacheEntry*)(void*)(cache + i*cacheEntrySize);
|
|
|
1febca |
entry->chunk_index = -1;
|
|
|
1febca |
entry->next = NULL;
|
|
|
1febca |
entry->prev = last;
|
|
|
1febca |
if (last) last->next = entry;
|
|
|
1febca |
last = entry;
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
void
|
|
|
1febca |
PackedSurface::Reader::close()
|
|
|
1febca |
{
|
|
|
1febca |
if (is_opened())
|
|
|
1febca |
{
|
|
|
1febca |
{
|
|
Rodolfo Ribeiro Gomes |
cfe072 |
std::lock_guard<std::mutex> lock(surface->mutex);</std::mutex>
|
|
|
1febca |
surface->readers.erase(this);
|
|
|
1febca |
}
|
|
|
1febca |
if (cache) delete[] cache;
|
|
|
1febca |
first = NULL;
|
|
|
1febca |
last = NULL;
|
|
|
1febca |
cache = NULL;
|
|
|
1febca |
surface = NULL;
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
Color
|
|
|
1febca |
PackedSurface::Reader::get_pixel(int x, int y) const
|
|
|
1febca |
{
|
|
|
1febca |
if (!is_opened())
|
|
|
1febca |
return Color();
|
|
|
1febca |
|
|
|
1febca |
if (x < 0)
|
|
|
1febca |
x = 0;
|
|
|
1febca |
if (x >= surface->width)
|
|
|
1febca |
x = surface->width-1;
|
|
|
1febca |
if (y < 0)
|
|
|
1febca |
y = 0;
|
|
|
1febca |
if (y >= surface->height)
|
|
|
1febca |
y = surface->height-1;
|
|
|
1febca |
|
|
|
1febca |
if (cache)
|
|
|
1febca |
{
|
|
|
1febca |
int chunk_index = x/ChunkSize + y/ChunkSize*surface->chunks_width;
|
|
|
1febca |
x %= ChunkSize;
|
|
|
1febca |
y %= ChunkSize;
|
|
|
1febca |
CacheEntry *entry = chunks[chunk_index];
|
|
|
1febca |
if (!entry)
|
|
|
1febca |
{
|
|
|
1febca |
const void *data;
|
|
|
1febca |
int size;
|
|
|
1febca |
bool compressed;
|
|
|
1febca |
surface->get_compressed_chunk(chunk_index, data, size, compressed);
|
|
|
1febca |
if (!compressed)
|
|
|
1febca |
return surface->get_pixel(&((const char*)data)[x*surface->pixel_size + y*surface->chunk_row_size]);
|
|
|
1febca |
|
|
|
1febca |
entry = last;
|
|
|
1febca |
if (entry->chunk_index >= 0)
|
|
|
1febca |
chunks[entry->chunk_index] = NULL;
|
|
|
1febca |
entry->chunk_index = chunk_index;
|
|
|
1febca |
chunks[chunk_index] = entry;
|
|
|
1febca |
zstreambuf::unpack(entry->data(), surface->chunk_size, data, size);
|
|
|
1febca |
}
|
|
|
1febca |
if (first != entry)
|
|
|
1febca |
{
|
|
|
1febca |
entry->prev->next = entry->next;
|
|
|
1febca |
(entry->next ? entry->next->prev : last) = entry->prev;
|
|
|
1febca |
|
|
|
1febca |
first->prev = entry;
|
|
|
1febca |
entry->prev = NULL;
|
|
|
1febca |
entry->next = first;
|
|
|
1febca |
first = entry;
|
|
|
1febca |
}
|
|
|
1febca |
return surface->get_pixel(entry->data(x*surface->pixel_size + y*surface->chunk_row_size));
|
|
|
1febca |
}
|
|
|
1febca |
else
|
|
|
1febca |
if (surface->pixel_size)
|
|
|
1febca |
{
|
|
|
1febca |
return surface->get_pixel(&surface->data[x*surface->pixel_size + y*surface->row_size]);
|
|
|
1febca |
}
|
|
|
1febca |
return surface->constant;
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
|
|
|
1febca |
PackedSurface::PackedSurface():
|
|
|
1febca |
width(0),
|
|
|
1febca |
height(0),
|
|
|
1febca |
channel_type(),
|
|
|
1febca |
pixel_size(0),
|
|
|
1febca |
row_size(0),
|
|
|
1febca |
chunk_size(0),
|
|
|
1febca |
chunk_row_size(0),
|
|
|
1febca |
chunks_width(0),
|
|
|
1febca |
chunks_height(0)
|
|
|
1febca |
{
|
|
|
1febca |
memset(channels, 0, sizeof(channels));
|
|
|
1febca |
memset(discrete_to_float, 0, sizeof(discrete_to_float));
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
PackedSurface::~PackedSurface()
|
|
|
1febca |
{
|
|
|
1febca |
clear();
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
|
|
|
1febca |
void
|
|
|
1febca |
PackedSurface::clear() {
|
|
|
1febca |
while(!readers.empty())
|
|
|
1febca |
(*readers.begin())->close();
|
|
|
1febca |
width = 0;
|
|
|
1febca |
height = 0;
|
|
|
1febca |
channel_type = ChannelUInt8;
|
|
|
1febca |
memset(channels, 0, sizeof(channels));
|
|
|
1febca |
memset(discrete_to_float, 0, sizeof(discrete_to_float));
|
|
|
1febca |
constant = Color();
|
|
|
1febca |
pixel_size = 0;
|
|
|
1febca |
row_size = 0;
|
|
|
1febca |
chunk_size = 0;
|
|
|
1febca |
chunk_row_size = 0;
|
|
|
1febca |
chunks_width = 0;
|
|
|
1febca |
chunks_height = 0;
|
|
|
1febca |
data.clear();
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
Color::value_type
|
|
|
1febca |
PackedSurface::get_channel(const void *pixel, int offset, ChannelType type, Color::value_type constant, const Color::value_type *discrete_to_float)
|
|
|
1febca |
{
|
|
|
1febca |
if (offset < 0)
|
|
|
1febca |
return constant;
|
|
|
1febca |
if (type == ChannelUInt8)
|
|
|
1febca |
return discrete_to_float[((const unsigned char*)pixel)[offset]];
|
|
|
1febca |
return *(const Color::value_type*)((const char*)pixel + offset);
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
void
|
|
|
1febca |
PackedSurface::set_channel(void *pixel, int offset, ChannelType type, Color::value_type color, const Color::value_type *discrete_to_float)
|
|
|
1febca |
{
|
|
|
1febca |
if (offset < 0)
|
|
|
1febca |
return;
|
|
|
1febca |
if (type == ChannelUInt8) {
|
|
|
1febca |
int i = 0;
|
|
|
1febca |
int j = 255;
|
|
|
1febca |
while(true)
|
|
|
1febca |
{
|
|
|
1febca |
int k = (i+j)/2;
|
|
|
1febca |
if (k == i) break;
|
|
|
1febca |
if (color < discrete_to_float[k]) j = k; else i = k;
|
|
|
1febca |
}
|
|
|
1febca |
int best_key = fabs(discrete_to_float[i] - color) < fabs(discrete_to_float[j] - color) ? i : j;
|
|
|
1febca |
((unsigned char*)pixel)[offset] = (unsigned char)best_key;
|
|
|
1febca |
return;
|
|
|
1febca |
}
|
|
|
1febca |
*(Color::value_type*)((char*)pixel + offset) = color;
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
Color
|
|
|
1febca |
PackedSurface::get_pixel(const void *pixel) const
|
|
|
1febca |
{
|
|
|
1febca |
return Color(
|
|
|
1febca |
get_channel(pixel, channels[0], channel_type, constant.get_r(), discrete_to_float),
|
|
|
1febca |
get_channel(pixel, channels[1], channel_type, constant.get_g(), discrete_to_float),
|
|
|
1febca |
get_channel(pixel, channels[2], channel_type, constant.get_b(), discrete_to_float),
|
|
|
1febca |
get_channel(pixel, channels[3], channel_type, constant.get_a(), discrete_to_float) );
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
void
|
|
|
1febca |
PackedSurface::set_pixel(void *pixel, const Color &color)
|
|
|
1febca |
{
|
|
|
1febca |
set_channel(pixel, channels[0], channel_type, color.get_r(), discrete_to_float);
|
|
|
1febca |
set_channel(pixel, channels[1], channel_type, color.get_g(), discrete_to_float);
|
|
|
1febca |
set_channel(pixel, channels[2], channel_type, color.get_b(), discrete_to_float);
|
|
|
1febca |
set_channel(pixel, channels[3], channel_type, color.get_a(), discrete_to_float);
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
void
|
|
|
1febca |
PackedSurface::get_compressed_chunk(int index, const void *&data, int &size, bool &compressed) const
|
|
|
1febca |
{
|
|
|
1febca |
assert(chunk_size);
|
|
|
1febca |
const int *chunks = (const int*)(const void*)&this->data.front();
|
|
|
1febca |
int begin = chunks[index];
|
|
|
1febca |
int end = chunks[index+1];
|
|
|
1febca |
data = &this->data[begin];
|
|
|
1febca |
size = end - begin;
|
|
|
1febca |
compressed = size != chunk_size;
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
void
|
|
|
1febca |
PackedSurface::set_pixels(const Color *pixels, int width, int height, int pitch) {
|
|
|
1febca |
clear();
|
|
|
1febca |
if (pixels == NULL || width <= 0 || height <= 0)
|
|
|
1febca |
return;
|
|
|
1febca |
|
|
|
1febca |
if (pitch == 0) pitch = sizeof(Color)*width;
|
|
|
1febca |
|
|
|
1febca |
// check format
|
|
|
1febca |
Color constant = *pixels;
|
|
|
1febca |
Color::value_type *constant_channels = (Color::value_type*)(void*)&constant;
|
|
|
1febca |
bool discrete = true;
|
|
|
1febca |
std::vector<discretehelper> discrete_values;</discretehelper>
|
|
|
1febca |
bool channels_equality[4][4];
|
|
|
1febca |
bool constant_equality[4];
|
|
|
1febca |
for(int i = 0; i < 4; ++i)
|
|
|
1febca |
{
|
|
|
1febca |
for(int j = 0; j < 4; ++j)
|
|
|
1febca |
channels_equality[i][j] = true;
|
|
|
1febca |
constant_equality[i] = true;
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
for(int row = 0; row < height; ++row) {
|
|
|
1febca |
for(const Color *color = (const Color*)((const char*)pixels + row*pitch), *end = color + width; color < end; ++color)
|
|
|
1febca |
{
|
|
|
1febca |
const Color::value_type *color_channels = (const Color::value_type*)(const void*)color;
|
|
|
1febca |
for(int i = 0; i < 4; ++i)
|
|
|
1febca |
{
|
|
|
1febca |
// compare channels
|
|
|
1febca |
for(int j = 0; j < i; ++j)
|
|
|
1febca |
if (channels_equality[i][j] && !approximate_equal_lp(color_channels[i], color_channels[j]))
|
|
|
1febca |
channels_equality[i][j] = false;
|
|
|
1febca |
|
|
|
1febca |
// compare with constant
|
|
|
1febca |
if (constant_equality[i] && !approximate_equal_lp(color_channels[i], constant_channels[i]))
|
|
|
1febca |
constant_equality[i] = false;
|
|
|
1febca |
|
|
|
1febca |
// check discrete
|
|
|
1febca |
if (discrete)
|
|
|
1febca |
{
|
|
|
1febca |
Color::value_type c = color_channels[i];
|
|
|
1febca |
if (discrete_values.empty()) {
|
|
|
1febca |
discrete_values.push_back(DiscreteHelper(c));
|
|
|
1febca |
} else {
|
|
|
1febca |
int i = 0;
|
|
|
1febca |
int j = discrete_values.size() - 1;
|
|
|
1febca |
while(true) {
|
|
|
1febca |
int k = (i+j)/2;
|
|
|
1febca |
if (k == i) break;
|
|
|
1febca |
if (c < discrete_values[k].min) j = k; else i = k;
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
if (discrete_values[i].in_range(c))
|
|
|
1febca |
++discrete_values[i].count;
|
|
|
1febca |
else
|
|
|
1febca |
if (discrete_values[j].in_range(c))
|
|
|
1febca |
++discrete_values[j].count;
|
|
|
1febca |
else
|
|
|
1febca |
{
|
|
|
1febca |
if (c < discrete_values[j].value)
|
|
|
1febca |
discrete_values.insert(discrete_values.begin() + j, DiscreteHelper(c));
|
|
|
1febca |
else
|
|
|
1febca |
discrete_values.push_back(DiscreteHelper(c));
|
|
|
1febca |
if (discrete_values.size() > 260) discrete = false;
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
this->channel_type = discrete ? ChannelUInt8 : ChannelFloat32;
|
|
|
1febca |
int channel_size = this->channel_type == ChannelUInt8 ? sizeof(unsigned char) : sizeof(ColorReal);
|
|
|
1febca |
|
|
|
1febca |
if (discrete) {
|
|
|
1febca |
while(discrete_values.size() > 256) {
|
|
|
1febca |
std::vector<discretehelper>::iterator min_i = discrete_values.begin();</discretehelper>
|
|
|
1febca |
for(std::vector<discretehelper>::iterator i = discrete_values.begin(); i != discrete_values.end(); ++i)</discretehelper>
|
|
|
1febca |
if (min_i->count > i->count)
|
|
|
1febca |
min_i = i;
|
|
|
1febca |
discrete_values.erase(min_i);
|
|
|
1febca |
}
|
|
|
1febca |
int index = 0;
|
|
|
1febca |
for(std::vector<discretehelper>::const_iterator i = discrete_values.begin(); i != discrete_values.end(); ++i, ++index)</discretehelper>
|
|
|
1febca |
discrete_to_float[index] = i->value;
|
|
|
1febca |
if (index > 0)
|
|
|
1febca |
for(; index < 256; ++index)
|
|
|
1febca |
discrete_to_float[index] = discrete_to_float[index - 1];
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
pixel_size = 0;
|
|
|
1febca |
for(int i = 0; i < 4; ++i) {
|
|
|
1febca |
channels[i] = i*channel_size;
|
|
|
1febca |
for(int j = 0; j < i; ++j)
|
|
|
1febca |
if (channels_equality[i][j])
|
|
|
1febca |
{ channels[i] = channels[j]; break; }
|
|
|
1febca |
if (constant_equality[i])
|
|
|
1febca |
channels[i] = -1;
|
|
|
e47a8f |
else
|
|
|
e47a8f |
constant_channels[i] = 0;
|
|
|
1febca |
if (channels[i] >= 0 && channels[i] + channel_size > pixel_size)
|
|
|
1febca |
pixel_size = channels[i] + channel_size;
|
|
|
1febca |
}
|
|
|
e47a8f |
this->constant = constant;
|
|
|
1febca |
this->width = width;
|
|
|
1febca |
this->height = height;
|
|
|
1febca |
row_size = width * pixel_size;
|
|
|
1febca |
|
|
|
2b738b |
const char *s;
|
|
|
2b738b |
bool gzip = (s = getenv("SYNFIG_PACK_IMAGES_GZIP")) && atoi(s) != 0;
|
|
|
2b738b |
bool split = (s = getenv("SYNFIG_PACK_IMAGES_SPLIT")) && atoi(s) != 0;
|
|
|
2b738b |
|
|
|
1febca |
if (pixel_size == 0) {
|
|
|
1febca |
// do nothing
|
|
|
1febca |
}
|
|
|
1febca |
else
|
|
|
2b738b |
if ((!gzip && !split) || std::max((width-1)/ChunkSize + 1, (height-1)/ChunkSize + 1)*CacheRows*ChunkSize*ChunkSize*16 > width*height)
|
|
|
1febca |
{
|
|
|
1febca |
// no compression
|
|
|
1febca |
data.resize(row_size*height);
|
|
|
1febca |
char *pixel = &data.front();
|
|
|
1febca |
for(int row = 0; row < height; ++row)
|
|
|
1febca |
for(const Color *color = (const Color*)((const char*)pixels + row*pitch), *end = color + width; color < end; ++color, pixel += pixel_size)
|
|
|
1febca |
set_pixel(pixel, *color);
|
|
|
1febca |
}
|
|
|
1febca |
else
|
|
|
1febca |
{
|
|
|
1febca |
// make chunks
|
|
|
1febca |
chunk_row_size = pixel_size*ChunkSize;
|
|
|
1febca |
chunk_size = chunk_row_size*ChunkSize;
|
|
|
1febca |
chunks_width = (width-1)/ChunkSize + 1;
|
|
|
1febca |
chunks_height = (height-1)/ChunkSize + 1;
|
|
|
1febca |
|
|
|
1febca |
int count = chunks_width*chunks_height;
|
|
|
1febca |
std::vector<char> data((count + 1)*sizeof(int), 0);</char>
|
|
|
1febca |
std::vector<char> chunk(chunk_size);</char>
|
|
|
1febca |
std::vector<char> compressed_chunk(2*chunk.size());</char>
|
|
|
1febca |
for(int i = 0; i < count; ++i) {
|
|
|
1febca |
char *pixel = &chunk.front();
|
|
|
1febca |
for(int r = 0; r < ChunkSize; ++r) {
|
|
|
1febca |
int x0 = i%chunks_width*ChunkSize;
|
|
|
1febca |
int y0 = i/chunks_width*ChunkSize;
|
|
|
1febca |
const Color *color = (const Color*)((const char*)pixels + (y0 + r)*pitch) + x0;
|
|
|
1febca |
for(int c = 0; c < ChunkSize; ++c, pixel += pixel_size, ++color)
|
|
|
2b738b |
if (x0+c < width && y0+r < height)
|
|
|
1febca |
set_pixel(pixel, *color);
|
|
|
1febca |
else
|
|
|
1febca |
set_pixel(pixel, Color());
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
2b738b |
const void* current_data = &chunk.front();
|
|
|
2b738b |
int size = (int)chunk.size();
|
|
|
2b738b |
|
|
|
2b738b |
if (gzip) {
|
|
|
2b738b |
int gzip_size = (int)zstreambuf::pack(&compressed_chunk.front(), compressed_chunk.size(), &chunk.front(), chunk.size(), true);
|
|
|
2b738b |
if (gzip_size <= (int)chunk.size()/4)
|
|
|
2b738b |
{
|
|
|
2b738b |
current_data = &compressed_chunk.front();
|
|
|
2b738b |
size = gzip_size;
|
|
|
2b738b |
}
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
((int*)(void*)&data.front())[i] = data.size();
|
|
|
1febca |
data.resize(data.size() + size);
|
|
|
1febca |
memcpy(&data[data.size() - size], current_data, size);
|
|
|
1febca |
}
|
|
|
1febca |
((int*)(void*)&data.front())[count] = data.size();
|
|
|
1febca |
|
|
|
1febca |
this->data = data;
|
|
|
1febca |
}
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
void
|
|
|
1febca |
PackedSurface::get_pixels(Color *target) const {
|
|
|
1febca |
if (target == NULL || width <= 0 || height <= 0)
|
|
|
1febca |
return;
|
|
|
1febca |
Reader reader(*this);
|
|
|
1febca |
Color *color = target;
|
|
|
1febca |
for(int y = 0; y < height; ++y)
|
|
|
1febca |
for(int x = 0; x < width; ++x, ++color)
|
|
|
1febca |
*color = reader.get_pixel(x, y);
|
|
|
1febca |
}
|
|
|
1febca |
|
|
|
1febca |
|
|
|
1febca |
|
|
|
1febca |
/* === E N T R Y P O I N T ================================================= */
|