/** * Configure a ViewPort for rendering (a part of) the map into a screenshot. * @param t Screenshot type * @param [out] vp Result viewport */ void SetupScreenshotViewport(ScreenshotType t, ViewPort *vp) { /* Determine world coordinates of screenshot */ if (t == SC_WORLD) { vp->zoom = ZOOM_LVL_WORLD_SCREENSHOT; TileIndex north_tile = _settings_game.construction.freeform_edges ? TileXY(1, 1) : TileXY(0, 0); TileIndex south_tile = MapSize() - 1; /* We need to account for a hill or high building at tile 0,0. */ int extra_height_top = TilePixelHeight(north_tile) + 150; /* If there is a hill at the bottom don't create a large black area. */ int reclaim_height_bottom = TilePixelHeight(south_tile); vp->virtual_left = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, 0).x; vp->virtual_top = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, extra_height_top).y; vp->virtual_width = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, 0).x - vp->virtual_left + 1; vp->virtual_height = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, reclaim_height_bottom).y - vp->virtual_top + 1; } else { vp->zoom = (t == SC_ZOOMEDIN) ? _settings_client.gui.zoom_min : ZOOM_LVL_VIEWPORT; Window *w = FindWindowById(WC_MAIN_WINDOW, 0); vp->virtual_left = w->viewport->virtual_left; vp->virtual_top = w->viewport->virtual_top; vp->virtual_width = w->viewport->virtual_width; vp->virtual_height = w->viewport->virtual_height; } /* Compute pixel coordinates */ vp->left = 0; vp->top = 0; vp->width = UnScaleByZoom(vp->virtual_width, vp->zoom); vp->height = UnScaleByZoom(vp->virtual_height, vp->zoom); vp->overlay = NULL; }
/** Make a zoomed-in screenshot of the currently visible area. */ static bool MakeZoomedInScreenshot() { Window *w = FindWindowById(WC_MAIN_WINDOW, 0); ViewPort vp; vp.zoom = _settings_client.gui.zoom_min; vp.left = w->viewport->left; vp.top = w->viewport->top; vp.virtual_left = w->viewport->virtual_left; vp.virtual_top = w->viewport->virtual_top; vp.virtual_width = w->viewport->virtual_width; vp.width = UnScaleByZoom(vp.virtual_width, vp.zoom); vp.virtual_height = w->viewport->virtual_height; vp.height = UnScaleByZoom(vp.virtual_height, vp.zoom); const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format; return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette); }
/** * Draws an image of a ship * @param v Front vehicle * @param left The minimum horizontal position * @param right The maximum horizontal position * @param y Vertical position to draw at * @param selection Selected vehicle to draw a frame around */ void DrawShipImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type) { bool rtl = _current_text_dir == TD_RTL; SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); int width = UnScaleByZoom(real_sprite->width, ZOOM_LVL_GUI); int x_offs = UnScaleByZoom(real_sprite->x_offs, ZOOM_LVL_GUI); int x = rtl ? right - width - x_offs : left - x_offs; DrawSprite(sprite, GetVehiclePalette(v), x, y + 10); if (v->index == selection) { x += x_offs; y += UnScaleByZoom(real_sprite->y_offs, ZOOM_LVL_GUI) + 10; DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleByZoom(real_sprite->height, ZOOM_LVL_GUI) + 1, COLOUR_WHITE, FR_BORDERONLY); } }
/** * Resizes the sprite in a very simple way, takes every n-th pixel and every n-th row * * @param sprite_src sprite to resize * @param zoom resizing scale * @return resized sprite */ static const SpriteLoader::Sprite *ResizeSprite(const SpriteLoader::Sprite *sprite_src, ZoomLevel zoom) { SpriteLoader::Sprite *sprite = MallocT<SpriteLoader::Sprite>(1); if (zoom == ZOOM_LVL_NORMAL) { memcpy(sprite, sprite_src, sizeof(*sprite)); uint size = sprite_src->height * sprite_src->width; sprite->data = MallocT<SpriteLoader::CommonPixel>(size); memcpy(sprite->data, sprite_src->data, size * sizeof(SpriteLoader::CommonPixel)); return sprite; } sprite->height = UnScaleByZoom(sprite_src->height, zoom); sprite->width = UnScaleByZoom(sprite_src->width, zoom); sprite->x_offs = UnScaleByZoom(sprite_src->x_offs, zoom); sprite->y_offs = UnScaleByZoom(sprite_src->y_offs, zoom); uint size = sprite->height * sprite->width; SpriteLoader::CommonPixel *dst = sprite->data = CallocT<SpriteLoader::CommonPixel>(size); const SpriteLoader::CommonPixel *src = (SpriteLoader::CommonPixel *)sprite_src->data; const SpriteLoader::CommonPixel *src_end = src + sprite_src->height * sprite_src->width; uint scaled_1 = ScaleByZoom(1, zoom); for (uint y = 0; y < sprite->height; y++) { if (src >= src_end) src = src_end - sprite_src->width; const SpriteLoader::CommonPixel *src_ln = src + sprite_src->width * scaled_1; for (uint x = 0; x < sprite->width; x++) { if (src >= src_ln) src = src_ln - 1; *dst = *src; dst++; src += scaled_1; } src = src_ln; } return sprite; }
Sprite *Blitter_8bppOptimized::Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator) { /* Make memory for all zoom-levels */ uint memory = sizeof(SpriteData); for (ZoomLevel i = ZOOM_LVL_BEGIN; i < ZOOM_LVL_END; i++) { memory += UnScaleByZoom(sprite->height, i) * UnScaleByZoom(sprite->width, i); } /* We have no idea how much memory we really need, so just guess something */ memory *= 5; /* Don't allocate memory each time, but just keep some * memory around as this function is called quite often * and the memory usage is quite low. */ static ReusableBuffer<byte> temp_buffer; SpriteData *temp_dst = (SpriteData *)temp_buffer.Allocate(memory); byte *dst = temp_dst->data; /* Make the sprites per zoom-level */ for (ZoomLevel i = ZOOM_LVL_BEGIN; i < ZOOM_LVL_END; i++) { /* Store the index table */ uint offset = dst - temp_dst->data; temp_dst->offset[i] = offset; /* cache values, because compiler can't cache it */ int scaled_height = UnScaleByZoom(sprite->height, i); int scaled_width = UnScaleByZoom(sprite->width, i); int scaled_1 = ScaleByZoom(1, i); for (int y = 0; y < scaled_height; y++) { uint trans = 0; uint pixels = 0; uint last_colour = 0; byte *count_dst = NULL; /* Store the scaled image */ const SpriteLoader::CommonPixel *src = &sprite->data[ScaleByZoom(y, i) * sprite->width]; const SpriteLoader::CommonPixel *src_end = &src[sprite->width]; for (int x = 0; x < scaled_width; x++) { uint colour = 0; /* Get the colour keeping in mind the zoom-level */ for (int j = 0; j < scaled_1; j++) { if (src->m != 0) colour = src->m; /* Because of the scaling it might happen we read outside the buffer. Avoid that. */ if (++src == src_end) break; } if (last_colour == 0 || colour == 0 || pixels == 255) { if (count_dst != NULL) { /* Write how many non-transparent bytes we get */ *count_dst = pixels; pixels = 0; count_dst = NULL; } /* As long as we find transparency bytes, keep counting */ if (colour == 0) { last_colour = 0; trans++; continue; } /* No longer transparency, so write the amount of transparent bytes */ *dst = trans; dst++; trans = 0; /* Reserve a byte for the pixel counter */ count_dst = dst; dst++; } last_colour = colour; pixels++; *dst = colour; dst++; } if (count_dst != NULL) *count_dst = pixels; /* Write line-ending */ *dst = 0; dst++; *dst = 0; dst++; } } uint size = dst - (byte *)temp_dst; /* Safety check, to make sure we guessed the size correctly */ assert(size < memory); /* Allocate the exact amount of memory we need */ Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + size); dest_sprite->height = sprite->height; dest_sprite->width = sprite->width; dest_sprite->x_offs = sprite->x_offs; dest_sprite->y_offs = sprite->y_offs; memcpy(dest_sprite->data, temp_dst, size); return dest_sprite; }