std::vector<uint32_t> TextTileSet::copy_glyph_bitmap(const ft::BitmapGlyph& glyph) const { auto bitmap_size = tile_width() * tile_height(); std::vector<uint32_t> bitmap_data(bitmap_size); const auto source_data = glyph.buffer(); if(source_data) { for(auto y = 0; y < glyph.rows(); ++y) { for(auto x = 0; x < glyph.width(); ++x) { auto x_pos = x + glyph.left(); auto y_pos = y + tile_height() - glyph.top() - m_vert_shift; auto index = x_pos + y_pos * tile_width(); if(index < bitmap_size && index >= 0) { bitmap_data[index] = 0x00FFFFFF | (source_data[x + y * glyph.pitch()] << 24); } } } } return bitmap_data; }
void TextTileSet::add_glyph(const TileLocation& location, unsigned int character) { auto glyph = std::static_pointer_cast<const ft::BitmapGlyph>( m_font_face->get_glyph(character)); auto bitmap_data = copy_glyph_bitmap(*glyph); Rectanglei tile_location(location.bottom_left.x * texture_width(), location.bottom_left.y * texture_height(), tile_width(), tile_height()); auto bound_texture = m_context->bind_texture_array_2d(*m_texture); bound_texture.update_data(tile_location, location.layer, 1, gl::Texture::DataPixelFormat::BGRA, gl::Texture::PixelType::UByte, bitmap_data.data()); }
void TextTileSet::compute_geometries(int min_slots) { auto g_character = std::static_pointer_cast<const ft::BitmapGlyph>(m_font_face->get_glyph('g')); int below_baseline = g_character->top() - g_character->rows(); if(below_baseline > 0) { below_baseline = 0; } m_vert_shift = -below_baseline; m_tile_height = m_vert_shift + m_font_face->line_height(); m_texture_layers = std::ceil(static_cast<float>(min_slots) / (tiles_per_line() * tile_lines())); m_cell_width = tile_width() / static_cast<double>(texture_width()); m_cell_height = tile_height() / static_cast<double>(texture_height()); auto tile_count = tiles_per_line() * tile_lines() * m_texture_layers; m_free_slots.resize(tile_count); m_tiles.resize(tile_count); }
void Save::save(const Image & in, const Image_Io_Frame_Info & frame) throw (Error) { //DJV_DEBUG("Save::save"); //DJV_DEBUG_PRINT("in = " << in); // Open the file. _open(_file.get(frame.frame)); // Convert the image. const Pixel_Data * p = ∈ if (in.info() != _info) { //DJV_DEBUG_PRINT("convert = " << _image); _image.zero(); Gl_Image::copy(in, _image); p = &_image; } // Write the file. const int w = p->w(), h = p->h(); const int channels = Pixel::channels(p->info().pixel); const int channel_bytes = Pixel::channel_bytes(p->info().pixel); const int bytes = Pixel::bytes(p->info().pixel); bool compress = _options.compression ? true : false; uint32_t length = 0; //DJV_DEBUG_PRINT("channels = " << channels); //DJV_DEBUG_PRINT("channel_bytes = " << channel_bytes); //DJV_DEBUG_PRINT("bytes = " << bytes); size_t pos = 0; pos = _io.position(); //DJV_DEBUG_PRINT("position = " << static_cast<int>(pos)); // 'FOR4' type _io.set_u8('F'); _io.set_u8('O'); _io.set_u8('R'); _io.set_u8('4'); // 'FOR4' length // NOTE: only reserved for now. _io.set_u32(length); // 'TBMP' type _io.set_u8('T'); _io.set_u8('B'); _io.set_u8('M'); _io.set_u8('P'); // Write tiles. V2i size = tile_size (w, h); // Y order. for (int y = 0; y < size.y; y++) { // X order. for (int x = 0; x < size.x; x++) { // Set tile coordinates. uint16_t xmin, xmax, ymin, ymax; // Set xmin and xmax. xmin = x * tile_width(); xmax = Math::min(xmin + tile_width(), w) - 1; // Set ymin and ymax. ymin = y * tile_height(); ymax = Math::min(ymin + tile_height(), h) - 1; // Set width and height. uint32_t tw = xmax - xmin + 1; uint32_t th = ymax - ymin + 1; // Set type. _io.set_u8('R'); _io.set_u8('G'); _io.set_u8('B'); _io.set_u8('A'); // Length. uint32_t length = tw * th * bytes; // Tile length. uint32_t tile_length = length; // Align. length = align_size(length, 4); // Append xmin, xmax, ymin and ymax. length += 8; // Tile compression. bool tile_compress = compress; // Set bytes. Memory_Buffer<uint8_t> tile(tile_length); uint8_t * out_p = tile(); // Handle 8-bit data. if (p->info().pixel == Pixel::RGB_U8 || p->info().pixel == Pixel::RGBA_U8) { if (tile_compress) { uint32_t index = 0, size = 0; // Set bytes. // NOTE: prevent buffer overrun. Memory_Buffer<uint8_t> tmp(tile_length * 2); // Map: RGB(A)8 RGBA to BGRA for (int c = (channels * channel_bytes) - 1; c >= 0; --c) { Memory_Buffer<uint8_t> in(tw * th); uint8_t * in_p = in(); // Data. for (uint16_t py = ymin; py <= ymax; py++) { const uint8_t * in_dy = p->data(0, py); for (uint16_t px = xmin; px <= xmax; px++) { // Get pixel. uint8_t pixel; const uint8_t * in_dx = in_dy + px * bytes + c; Memory::copy(in_dx, &pixel, 1); // Set pixel. *in_p++ = pixel; } } // Compress size = rle_save(in(), tmp() + index, tw * th); index += size; } // If size exceeds tile length use uncompressed. if (index < tile_length) { Memory::copy(tmp(), tile(), index); // Set tile length. tile_length = index; // Append xmin, xmax, ymin and ymax. length = index + 8; // Set length. uint32_t align = align_size(length, 4); if (align > length) { out_p = tile() + index; // Pad. for (int i = 0; i < static_cast<int>(align - length); i++) { *out_p++ = '\0'; tile_length++; } } } else { tile_compress = false; } } if (!tile_compress) { for (uint16_t py = ymin; py <= ymax; py++) { const uint8_t * in_dy = p->data(0, py); for (uint16_t px = xmin; px <= xmax; px++) { // Map: RGB(A)8 RGBA to BGRA for (int c = channels - 1; c >= 0; --c) { // Get pixel. uint8_t pixel; const uint8_t * in_dx = in_dy + px * bytes + c * channel_bytes; Memory::copy(in_dx, &pixel, 1); // Set pixel. *out_p++ = pixel; } } } } } // Handle 16-bit data. else if ( p->info().pixel == Pixel::RGB_U16 || p->info().pixel == Pixel::RGBA_U16) { if (tile_compress) { uint32_t index = 0, size = 0; // Set bytes. // NOTE: prevent buffer overrun. Memory_Buffer<uint8_t> tmp(tile_length * 2); // Set map. int* map = NULL; if (Memory::endian () == Memory::LSB) { int rgb16[] = { 0, 2, 4, 1, 3, 5 }; int rgba16[] = { 0, 2, 4, 7, 1, 3, 5, 6 }; if (_info.pixel == Pixel::RGB_U16) { map = rgb16; } else { map = rgba16; } } else { int rgb16[] = { 1, 3, 5, 0, 2, 4 }; int rgba16[] = { 1, 3, 5, 7, 0, 2, 4, 6 }; if (_info.pixel == Pixel::RGB_U16) { map = rgb16; } else { map = rgba16; } } // Map: RGB(A)16 RGBA to BGRA for (int c = (channels * channel_bytes) - 1; c >= 0; --c) { int mc = map[c]; Memory_Buffer<uint8_t> in(tw * th); uint8_t * in_p = in(); // Data. for (uint16_t py = ymin; py <= ymax; py++) { const uint8_t * in_dy = p->data(0, py); for (uint16_t px = xmin; px <= xmax; px++) { // Get pixel. uint8_t pixel; const uint8_t * in_dx = in_dy + px * bytes + mc; Memory::copy(in_dx, &pixel, 1); // Set pixel. *in_p++ = pixel; } } // Compress size = rle_save(in(), tmp() + index, tw * th); index += size; } // If size exceeds tile length use uncompressed. if (index < tile_length) { Memory::copy(tmp(), tile(), index); // Set tile length. tile_length = index; // Append xmin, xmax, ymin and ymax. length = index + 8; // Set length. uint32_t align = align_size(length, 4); if (align > length) { out_p = tile() + index; // Pad. for ( int i = 0; i < static_cast<int>(align - length); i++) { *out_p++ = '\0'; tile_length++; } } } else { tile_compress = false; } } if (!tile_compress) { for (uint16_t py = ymin; py <= ymax; py++) { const uint8_t * in_dy = p->data(0, py); for (uint16_t px = xmin; px <= xmax; px++) { // Map: RGB(A)16 RGBA to BGRA for (int c = channels - 1; c >= 0; --c) { uint16_t pixel; const uint8_t * in_dx = in_dy + px * bytes + c * channel_bytes; if (Memory::endian () == Memory::LSB) { Memory::endian(in_dx, &pixel, 1, 2); } else { Memory::copy(in_dx, &pixel, 2); } // Set pixel. *out_p++ = pixel; out_p++; } } } } } // Set length. _io.set_u32(length); // Set xmin, xmax, ymin and ymax. _io.set_u16(xmin); _io.set_u16(ymin); _io.set_u16(xmax); _io.set_u16(ymax); // Write. _io.set(tile(), tile_length); } } // Set FOR4 CIMG and FOR4 TBMP size uint32_t p0 = _io.position() - 8; uint32_t p1 = p0 - pos; // NOTE: FOR4 <size> CIMG _io.position (4); _io.set_u32 (p0); // NOTE: FOR4 <size> TBMP _io.position (pos + 4); _io.set_u32 (p1); _io.close(); }