Initial commit
This commit is contained in:
923
engines/ags/engine/gfx/ali_3d_scummvm.cpp
Normal file
923
engines/ags/engine/gfx/ali_3d_scummvm.cpp
Normal file
@@ -0,0 +1,923 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/engine/gfx/gfxfilter_scummvm_renderer.h"
|
||||
#include "ags/engine/gfx/ali_3d_scummvm.h"
|
||||
#include "common/std/algorithm.h"
|
||||
#include "ags/engine/ac/sys_events.h"
|
||||
#include "ags/engine/gfx/gfxfilter_scummvm_renderer.h"
|
||||
#include "ags/engine/gfx/gfx_util.h"
|
||||
#include "ags/engine/platform/base/ags_platform_driver.h"
|
||||
#include "ags/engine/platform/base/sys_main.h"
|
||||
#include "ags/engine/ac/timer.h"
|
||||
#include "ags/ags.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
namespace ALSW {
|
||||
|
||||
using namespace Shared;
|
||||
|
||||
static RGB faded_out_palette[256];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ScummVMRendererGraphicsDriver
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
ScummVMRendererGraphicsDriver::ScummVMRendererGraphicsDriver() {
|
||||
_tint_red = 0;
|
||||
_tint_green = 0;
|
||||
_tint_blue = 0;
|
||||
virtualScreen = nullptr;
|
||||
_stageVirtualScreen = nullptr;
|
||||
}
|
||||
|
||||
ScummVMRendererGraphicsDriver::~ScummVMRendererGraphicsDriver() {
|
||||
delete _screen;
|
||||
ScummVMRendererGraphicsDriver::UnInit();
|
||||
}
|
||||
|
||||
bool ScummVMRendererGraphicsDriver::IsModeSupported(const DisplayMode &mode) {
|
||||
if (mode.Width <= 0 || mode.Height <= 0 || mode.ColorDepth <= 0) {
|
||||
warning("Invalid resolution parameters: %d x %d x %d",
|
||||
mode.Width, mode.Height, mode.ColorDepth);
|
||||
return false;
|
||||
}
|
||||
|
||||
Graphics::PixelFormat format;
|
||||
return ::AGS::g_vm->getPixelFormat(mode.ColorDepth, format);
|
||||
}
|
||||
|
||||
int ScummVMRendererGraphicsDriver::GetDisplayDepthForNativeDepth(int native_color_depth) const {
|
||||
// TODO: check for device caps to know which depth is supported?
|
||||
if (native_color_depth > 8)
|
||||
return 32;
|
||||
return native_color_depth;
|
||||
}
|
||||
|
||||
IGfxModeList *ScummVMRendererGraphicsDriver::GetSupportedModeList(int color_depth) {
|
||||
std::vector<DisplayMode> modes;
|
||||
sys_get_desktop_modes(modes, color_depth);
|
||||
if ((modes.size() == 0) && color_depth == 32) {
|
||||
// Pretend that 24-bit are 32-bit
|
||||
sys_get_desktop_modes(modes, 24);
|
||||
for (auto &m : modes)
|
||||
m.ColorDepth = 32;
|
||||
}
|
||||
return new ScummVMRendererGfxModeList(modes);
|
||||
}
|
||||
|
||||
PGfxFilter ScummVMRendererGraphicsDriver::GetGraphicsFilter() const {
|
||||
return _filter;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::SetGraphicsFilter(PSDLRenderFilter filter) {
|
||||
_filter = filter;
|
||||
OnSetFilter();
|
||||
|
||||
// TODO: support separate nearest and linear filters, initialize hint by calls to filter object
|
||||
// e.g like D3D and OGL filters act
|
||||
// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
|
||||
// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother.
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::SetTintMethod(TintMethod /*method*/) {
|
||||
// TODO: support new D3D-style tint method
|
||||
}
|
||||
|
||||
bool ScummVMRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode) {
|
||||
ReleaseDisplayMode();
|
||||
|
||||
set_color_depth(mode.ColorDepth);
|
||||
|
||||
if (_initGfxCallback != nullptr)
|
||||
_initGfxCallback(nullptr);
|
||||
|
||||
if (!IsModeSupported(mode))
|
||||
return false;
|
||||
|
||||
_capsVsync = true; // reset vsync flag, allow to try setting again
|
||||
const int driver = GFX_SCUMMVM;
|
||||
if (set_gfx_mode(driver, mode.Width, mode.Height, mode.ColorDepth) != 0)
|
||||
return false;
|
||||
|
||||
if (g_system->hasFeature(OSystem::kFeatureVSync)) {
|
||||
g_system->beginGFXTransaction();
|
||||
g_system->setFeatureState(OSystem::kFeatureVSync, mode.Vsync);
|
||||
g_system->endGFXTransaction();
|
||||
}
|
||||
else {
|
||||
_capsVsync = false;
|
||||
Debug::Printf(kDbgMsg_Warn, "WARNING: Vertical sync is not supported. Setting will be kept at driver default.");
|
||||
}
|
||||
|
||||
OnInit();
|
||||
OnModeSet(mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::UpdateDeviceScreen(const Size &screen_sz) {
|
||||
_mode.Width = screen_sz.Width;
|
||||
_mode.Height = screen_sz.Height;
|
||||
#if AGS_PLATFORM_OS_ANDROID
|
||||
SDL_RenderSetLogicalSize(_renderer, _mode.Width, _mode.Height);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::CreateVirtualScreen() {
|
||||
if (!IsNativeSizeValid())
|
||||
return;
|
||||
DestroyVirtualScreen();
|
||||
// Initialize virtual screen; size is equal to native resolution
|
||||
const int vscreen_w = _srcRect.GetWidth();
|
||||
const int vscreen_h = _srcRect.GetHeight();
|
||||
_origVirtualScreen.reset(new Bitmap(vscreen_w, vscreen_h, _srcColorDepth));
|
||||
virtualScreen = _origVirtualScreen.get();
|
||||
_stageVirtualScreen = virtualScreen;
|
||||
|
||||
|
||||
_lastTexPixels = nullptr;
|
||||
_lastTexPitch = -1;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::DestroyVirtualScreen() {
|
||||
delete[] _fakeTexBitmap; // don't use destroy_bitmap(), because it's a fake structure
|
||||
_fakeTexBitmap = nullptr;
|
||||
|
||||
_origVirtualScreen.reset();
|
||||
virtualScreen = nullptr;
|
||||
_stageVirtualScreen = nullptr;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::ReleaseDisplayMode() {
|
||||
OnModeReleased();
|
||||
ClearDrawLists();
|
||||
}
|
||||
|
||||
bool ScummVMRendererGraphicsDriver::SetNativeResolution(const GraphicResolution &native_res) {
|
||||
OnSetNativeRes(native_res);
|
||||
CreateVirtualScreen();
|
||||
return !_srcRect.IsEmpty();
|
||||
}
|
||||
|
||||
bool ScummVMRendererGraphicsDriver::SetRenderFrame(const Rect &dst_rect) {
|
||||
OnSetRenderFrame(dst_rect);
|
||||
return !_dstRect.IsEmpty();
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::ClearRectangle(int /*x1*/, int /*y1*/, int /*x2*/, int /*y2*/, RGB * /*colorToUse*/) {
|
||||
// TODO: but maybe is not necessary, as we use SDL_Renderer with accelerated gfx here?
|
||||
// See SDL_RenderDrawRect
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::UnInit() {
|
||||
OnUnInit();
|
||||
ReleaseDisplayMode();
|
||||
DestroyVirtualScreen();
|
||||
|
||||
sys_window_destroy();
|
||||
}
|
||||
|
||||
bool ScummVMRendererGraphicsDriver::SupportsGammaControl() {
|
||||
return _hasGamma;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::SetGamma(int newGamma) {
|
||||
if (!_hasGamma) {
|
||||
return;
|
||||
}
|
||||
#ifdef TODO
|
||||
uint16 gamma_red[256];
|
||||
uint16 gamma_green[256];
|
||||
uint16 gamma_blue[256];
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
gamma_red[i] = MIN(((int)_defaultGammaRed[i] * newGamma) / 100, 0xffff);
|
||||
gamma_green[i] = MIN(((int)_defaultGammaGreen[i] * newGamma) / 100, 0xffff);
|
||||
gamma_blue[i] = MIN(((int)_defaultGammaBlue[i] * newGamma) / 100, 0xffff);
|
||||
}
|
||||
|
||||
SDL_SetWindowGammaRamp(sys_get_window(), gamma_red, gamma_green, gamma_blue);
|
||||
_gamma = newGamma;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ScummVMRendererGraphicsDriver::DoesSupportVsyncToggle() {
|
||||
return g_system->hasFeature(OSystem::kFeatureVSync);
|
||||
}
|
||||
|
||||
bool ScummVMRendererGraphicsDriver::SetVsyncImpl(bool enabled, bool &vsync_res) {
|
||||
if (g_system->hasFeature(OSystem::kFeatureVSync)) {
|
||||
g_system->beginGFXTransaction();
|
||||
g_system->setFeatureState(OSystem::kFeatureVSync, enabled);
|
||||
g_system->endGFXTransaction();
|
||||
|
||||
vsync_res = g_system->getFeatureState(OSystem::kFeatureVSync);
|
||||
if (!vsync_res)
|
||||
Debug::Printf(kDbgMsg_Warn, "Renderer: SetVsync (%d) failed", enabled);
|
||||
return vsync_res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int ScummVMRendererGraphicsDriver::GetCompatibleBitmapFormat(int color_depth) {
|
||||
return color_depth;
|
||||
}
|
||||
|
||||
IDriverDependantBitmap *ScummVMRendererGraphicsDriver::CreateDDB(int width, int height, int color_depth, bool opaque) {
|
||||
return new ALSoftwareBitmap(width, height, color_depth, opaque);
|
||||
}
|
||||
|
||||
IDriverDependantBitmap *ScummVMRendererGraphicsDriver::CreateDDBFromBitmap(Bitmap *bitmap, bool has_alpha, bool opaque) {
|
||||
return new ALSoftwareBitmap(bitmap, has_alpha, opaque);
|
||||
}
|
||||
|
||||
IDriverDependantBitmap *ScummVMRendererGraphicsDriver::CreateRenderTargetDDB(int width, int height, int color_depth, bool opaque) {
|
||||
return new ALSoftwareBitmap(width, height, color_depth, opaque);
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::UpdateDDBFromBitmap(IDriverDependantBitmap *bitmapToUpdate, Bitmap *bitmap, bool has_alpha) {
|
||||
ALSoftwareBitmap *alSwBmp = (ALSoftwareBitmap *)bitmapToUpdate;
|
||||
alSwBmp->_bmp = bitmap;
|
||||
alSwBmp->_hasAlpha = has_alpha;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::DestroyDDB(IDriverDependantBitmap *bitmap) {
|
||||
delete (ALSoftwareBitmap *)bitmap;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::InitSpriteBatch(size_t index, const SpriteBatchDesc &desc) {
|
||||
if (_spriteBatches.size() <= index)
|
||||
_spriteBatches.resize(index + 1);
|
||||
ALSpriteBatch &batch = _spriteBatches[index];
|
||||
batch.ID = index;
|
||||
|
||||
// Apply parent batch's settings, if preset;
|
||||
Rect viewport = desc.Viewport;
|
||||
SpriteTransform transform = desc.Transform;
|
||||
Bitmap *parent_surf = virtualScreen;
|
||||
if (desc.Parent != UINT32_MAX) {
|
||||
const auto &parent = _spriteBatches[desc.Parent];
|
||||
if (parent.Surface)
|
||||
parent_surf = parent.Surface.get();
|
||||
// NOTE: we prioritize parent's surface size as a dest viewport,
|
||||
// because parent may have a scheduled scaled blit.
|
||||
if (viewport.IsEmpty())
|
||||
viewport = parent_surf ? RectWH(parent_surf->GetSize()) : RectWH(parent.Viewport.GetSize());
|
||||
} else if (viewport.IsEmpty()) {
|
||||
viewport = _srcRect;
|
||||
}
|
||||
|
||||
// Calculate expected source surf size, based on dest viewport and scaling
|
||||
const int src_w = viewport.GetWidth() / transform.ScaleX;
|
||||
const int src_h = viewport.GetHeight() / transform.ScaleY;
|
||||
|
||||
// Initialize batch surface, depending on the batch description.
|
||||
// Surface was prepared externally (common for room cameras)
|
||||
if (desc.Surface != nullptr) {
|
||||
batch.Surface = desc.Surface;
|
||||
batch.Opaque = true;
|
||||
batch.IsParentRegion = false;
|
||||
}
|
||||
// In case something was not initialized
|
||||
else if (desc.Viewport.IsEmpty() || !virtualScreen) {
|
||||
batch.Surface.reset();
|
||||
batch.Opaque = false;
|
||||
batch.IsParentRegion = false;
|
||||
}
|
||||
// Drawing directly on a viewport without transformation (other than offset):
|
||||
// then make a subbitmap of the parent surface (virtualScreen or else).
|
||||
else if (transform.ScaleX == 1.f && transform.ScaleY == 1.f) {
|
||||
// We need this subbitmap for plugins, which use _stageVirtualScreen and are unaware of possible multiple viewports;
|
||||
// TODO: there could be ways to optimize this further, but best is to update plugin rendering hooks (and upgrade plugins)
|
||||
if (!batch.Surface || !batch.IsParentRegion ||
|
||||
(!batch.Surface->IsSameBitmap(parent_surf)) ||
|
||||
(batch.Surface->GetSize() != Size(src_w, src_h)) ||
|
||||
(batch.Surface->GetSubOffset() != viewport.GetLT())) {
|
||||
batch.Surface.reset(BitmapHelper::CreateSubBitmap(parent_surf, viewport));
|
||||
}
|
||||
batch.Opaque = true;
|
||||
batch.IsParentRegion = true;
|
||||
// Because we sub-bitmap to viewport, render offsets should account for that
|
||||
transform.X -= viewport.Left;
|
||||
transform.Y -= viewport.Top;
|
||||
}
|
||||
// No surface prepared and has transformation other than offset:
|
||||
// then create exclusive intermediate bitmap.
|
||||
else {
|
||||
if (!batch.Surface || batch.IsParentRegion || (batch.Surface->GetSize() != Size(src_w, src_h))) {
|
||||
batch.Surface.reset(new Bitmap(src_w, src_h, _srcColorDepth));
|
||||
}
|
||||
batch.Opaque = false;
|
||||
batch.IsParentRegion = false;
|
||||
}
|
||||
|
||||
batch.Viewport = viewport;
|
||||
batch.Transform = transform;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::ResetAllBatches() {
|
||||
// NOTE: we don't release batches themselves here, only sprite lists.
|
||||
// This is because we cache batch surfaces, for performance reasons.
|
||||
_spriteList.clear();
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::DrawSprite(int x, int y, IDriverDependantBitmap *bitmap) {
|
||||
assert(_actSpriteBatch != UINT32_MAX);
|
||||
_spriteList.push_back(ALDrawListEntry((ALSoftwareBitmap *)bitmap, _actSpriteBatch, x, y));
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::SetScreenFade(int /*red*/, int /*green*/, int /*blue*/) {
|
||||
// TODO: was not necessary atm
|
||||
// TODO: checkme later
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::SetScreenTint(int red, int green, int blue) {
|
||||
assert(_actSpriteBatch != UINT32_MAX);
|
||||
_tint_red = red;
|
||||
_tint_green = green;
|
||||
_tint_blue = blue;
|
||||
if (((_tint_red > 0) || (_tint_green > 0) || (_tint_blue > 0)) && (_srcColorDepth > 8)) {
|
||||
_spriteList.push_back(
|
||||
ALDrawListEntry(reinterpret_cast<ALSoftwareBitmap *>(DRAWENTRY_TINT), _actSpriteBatch, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::SetStageScreen(const Size & /*sz*/, int /*x*/, int /*y*/) {
|
||||
// unsupported, as using _stageVirtualScreen instead
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::RenderToBackBuffer() {
|
||||
// Close unended batches, and issue a warning
|
||||
assert(_actSpriteBatch == UINT32_MAX);
|
||||
while (_actSpriteBatch != UINT32_MAX)
|
||||
EndSpriteBatch();
|
||||
|
||||
if (_spriteBatchDesc.size() == 0) {
|
||||
ClearDrawLists();
|
||||
return; // no batches - no render
|
||||
}
|
||||
|
||||
// Render all the sprite batches with necessary transformations
|
||||
//
|
||||
// NOTE: that's not immediately clear whether it would be faster to first draw upon a camera-sized
|
||||
// surface then stretch final result to the viewport on screen, or stretch-blit each individual
|
||||
// sprite right onto screen bitmap. We'd need to do proper profiling to know that.
|
||||
// An important thing is that Allegro does not provide stretching functions for drawing sprites
|
||||
// with blending and translucency; it seems you'd have to first stretch the original sprite onto a
|
||||
// temp buffer and then TransBlendBlt / LitBlendBlt it to the final destination. Of course, doing
|
||||
// that here would slow things down significantly, so if we ever go that way sprite caching will
|
||||
// be required (similarly to how AGS caches flipped/scaled object sprites now for).
|
||||
//
|
||||
|
||||
const size_t last_batch_to_rend = _spriteBatchDesc.size() - 1;
|
||||
for (size_t cur_bat = 0u, last_bat = 0u, cur_spr = 0u; last_bat <= last_batch_to_rend;) {
|
||||
// Test if we are entering this batch (and not continuing after coming back from nested)
|
||||
if (cur_spr <= _spriteBatchRange[cur_bat].first) {
|
||||
const auto &batch = _spriteBatches[cur_bat];
|
||||
// Prepare the transparent surface
|
||||
if (batch.Surface && !batch.Opaque)
|
||||
batch.Surface->ClearTransparent();
|
||||
}
|
||||
|
||||
// Render immediate batch sprites, if any, update cur_spr iterator
|
||||
if ((cur_spr < _spriteList.size()) && (cur_bat == _spriteList[cur_spr].node)) {
|
||||
const auto &batch = _spriteBatches[cur_bat];
|
||||
const auto &batch_desc = _spriteBatchDesc[cur_bat];
|
||||
Bitmap *surface = batch.Surface.get();
|
||||
Bitmap *parent_surf = ((batch_desc.Parent != UINT32_MAX) && _spriteBatches[batch_desc.Parent].Surface) ? _spriteBatches[batch_desc.Parent].Surface.get() : virtualScreen;
|
||||
const Rect &viewport = batch.Viewport;
|
||||
const SpriteTransform &transform = batch.Transform;
|
||||
|
||||
_rendSpriteBatch = batch.ID;
|
||||
parent_surf->SetClip(viewport); // CHECKME: this is not exactly correct?
|
||||
if (surface && !batch.IsParentRegion) {
|
||||
_stageVirtualScreen = surface;
|
||||
cur_spr = RenderSpriteBatch(batch, cur_spr, surface, transform.X, transform.Y);
|
||||
} else {
|
||||
_stageVirtualScreen = surface ? surface : parent_surf;
|
||||
cur_spr = RenderSpriteBatch(batch, cur_spr, _stageVirtualScreen, transform.X, transform.Y);
|
||||
}
|
||||
}
|
||||
|
||||
// Test if we're exiting current batch (and not going into nested ones):
|
||||
// if there's no sprites belonging to this batch (direct, or nested),
|
||||
// and if there's no nested batches (even if empty ones)
|
||||
const uint32_t was_bat = cur_bat;
|
||||
while ((cur_bat != UINT32_MAX) && (cur_spr >= _spriteBatchRange[cur_bat].second) &&
|
||||
((last_bat == last_batch_to_rend) || (_spriteBatchDesc[last_bat + 1].Parent != cur_bat))) {
|
||||
const auto &batch = _spriteBatches[cur_bat];
|
||||
const auto &batch_desc = _spriteBatchDesc[cur_bat];
|
||||
Bitmap *surface = batch.Surface.get();
|
||||
Bitmap *parent_surf = ((batch_desc.Parent != UINT32_MAX) && _spriteBatches[batch_desc.Parent].Surface) ? _spriteBatches[batch_desc.Parent].Surface.get() : virtualScreen;
|
||||
const Rect &viewport = batch.Viewport;
|
||||
|
||||
// If we're not drawing directly to the subregion of a parent surface,
|
||||
// then blit our own surface to the parent's
|
||||
if (surface && !batch.IsParentRegion) {
|
||||
parent_surf->StretchBlt(surface, viewport, batch.Opaque ? kBitmap_Copy : kBitmap_Transparency);
|
||||
}
|
||||
|
||||
// Back to the parent batch
|
||||
cur_bat = batch_desc.Parent;
|
||||
}
|
||||
|
||||
// If we stayed at the same batch, this means that there are still nested batches;
|
||||
// if there's no batches in the stack left, this means we got to move forward anyway.
|
||||
if ((was_bat == cur_bat) || (cur_bat == UINT32_MAX)) {
|
||||
cur_bat = ++last_bat;
|
||||
}
|
||||
}
|
||||
|
||||
_stageVirtualScreen = virtualScreen;
|
||||
_rendSpriteBatch = UINT32_MAX;
|
||||
ClearDrawLists();
|
||||
}
|
||||
|
||||
size_t ScummVMRendererGraphicsDriver::RenderSpriteBatch(const ALSpriteBatch &batch, size_t from, Bitmap *surface, int surf_offx, int surf_offy) {
|
||||
for (; (from < _spriteList.size()) && (_spriteList[from].node == batch.ID); ++from) {
|
||||
const auto &sprite = _spriteList[from];
|
||||
if (sprite.ddb == nullptr) {
|
||||
if (_spriteEvtCallback)
|
||||
_spriteEvtCallback(sprite.x, sprite.y);
|
||||
else
|
||||
error("Unhandled attempt to draw null sprite");
|
||||
// Stage surface could have been replaced by plugin
|
||||
surface = _stageVirtualScreen;
|
||||
continue;
|
||||
} else if (sprite.ddb == reinterpret_cast<ALSoftwareBitmap *>(DRAWENTRY_TINT)) {
|
||||
// draw screen tint fx
|
||||
set_trans_blender(_tint_red, _tint_green, _tint_blue, 0);
|
||||
surface->LitBlendBlt(surface, 0, 0, 128);
|
||||
continue;
|
||||
}
|
||||
|
||||
ALSoftwareBitmap *bitmap = sprite.ddb;
|
||||
int drawAtX = sprite.x + surf_offx;
|
||||
int drawAtY = sprite.y + surf_offy;
|
||||
|
||||
if (bitmap->_alpha == 0) {
|
||||
} // fully transparent, do nothing
|
||||
else if ((bitmap->_opaque) && (bitmap->_bmp == surface) && (bitmap->_alpha == 255)) {
|
||||
} else if (bitmap->_opaque) {
|
||||
surface->Blit(bitmap->_bmp, 0, 0, drawAtX, drawAtY, bitmap->_bmp->GetWidth(), bitmap->_bmp->GetHeight());
|
||||
// TODO: we need to also support non-masked translucent blend, but...
|
||||
// Allegro 4 **does not have such function ready** :( (only masked blends, where it skips magenta pixels);
|
||||
// I am leaving this problem for the future, as coincidentally software mode does not need this atm.
|
||||
} else if (bitmap->_hasAlpha) {
|
||||
if (bitmap->_alpha == 255) // no global transparency, simple alpha blend
|
||||
set_alpha_blender();
|
||||
else
|
||||
set_blender_mode(kArgbToRgbBlender, 0, 0, 0, bitmap->_alpha);
|
||||
|
||||
surface->TransBlendBlt(bitmap->_bmp, drawAtX, drawAtY);
|
||||
} else {
|
||||
// here _transparency is used as alpha (between 1 and 254), but 0 means opaque!
|
||||
GfxUtil::DrawSpriteWithTransparency(surface, bitmap->_bmp, drawAtX, drawAtY,
|
||||
bitmap->_alpha);
|
||||
}
|
||||
}
|
||||
return from;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::copySurface(const Graphics::Surface &src, bool mode) {
|
||||
assert(src.w == _screen->w && src.h == _screen->h && src.pitch == _screen->pitch);
|
||||
const uint32 *srcP = (const uint32 *)src.getPixels();
|
||||
uint32 *destP = (uint32 *)_screen->getPixels();
|
||||
uint32 pixel;
|
||||
int x1 = 9999, y1 = 9999, x2 = -1, y2 = -1;
|
||||
|
||||
for (int y = 0; y < src.h; ++y) {
|
||||
for (int x = 0; x < src.w; ++x, ++srcP, ++destP) {
|
||||
if (!mode) {
|
||||
pixel = (*srcP & 0xff00ff00) |
|
||||
((*srcP & 0xff) << 16) |
|
||||
((*srcP >> 16) & 0xff);
|
||||
} else {
|
||||
pixel = ((*srcP & 0xffffff) << 8) |
|
||||
((*srcP >> 24) & 0xff);
|
||||
}
|
||||
|
||||
if (*destP != pixel) {
|
||||
*destP = pixel;
|
||||
x1 = MIN(x1, x);
|
||||
y1 = MIN(y1, y);
|
||||
x2 = MAX(x2, x);
|
||||
y2 = MAX(y2, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x2 != -1)
|
||||
_screen->addDirtyRect(Common::Rect(x1, y1, x2 + 1, y2 + 1));
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::Present(int xoff, int yoff, Shared::GraphicFlip flip) {
|
||||
Graphics::Surface *srcTransformed = nullptr;
|
||||
if (xoff != 0 || yoff != 0 || flip != Shared::kFlip_None) {
|
||||
srcTransformed = new Graphics::Surface();
|
||||
srcTransformed->copyFrom(virtualScreen->GetAllegroBitmap()->getSurface());
|
||||
switch(flip) {
|
||||
case kFlip_Horizontal:
|
||||
srcTransformed->flipHorizontal(Common::Rect(srcTransformed->w, srcTransformed->h));
|
||||
break;
|
||||
case kFlip_Vertical:
|
||||
srcTransformed->flipVertical(Common::Rect(srcTransformed->w, srcTransformed->h));
|
||||
break;
|
||||
case kFlip_Both:
|
||||
srcTransformed->flipHorizontal(Common::Rect(srcTransformed->w, srcTransformed->h));
|
||||
srcTransformed->flipVertical(Common::Rect(srcTransformed->w, srcTransformed->h));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
srcTransformed->move(xoff, yoff, srcTransformed->h);
|
||||
}
|
||||
|
||||
const Graphics::Surface &src = srcTransformed ?
|
||||
*srcTransformed :
|
||||
virtualScreen->GetAllegroBitmap()->getSurface();
|
||||
|
||||
enum {
|
||||
kRenderInitial, kRenderDirect, kRenderToABGR, kRenderToRGBA,
|
||||
kRenderOther
|
||||
} renderMode;
|
||||
|
||||
// Check for rendering to use. The virtual screen can change, so I'm
|
||||
// playing it safe and checking the render mode for each frame
|
||||
const Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
|
||||
|
||||
if (src.format == screenFormat) {
|
||||
// The virtual surface can be directly blitted to the screen
|
||||
renderMode = kRenderDirect;
|
||||
} else if (src.format != Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)) {
|
||||
// Not a 32-bit surface, so will have to use an intermediate
|
||||
// surface to correct the virtual screen to the correct format
|
||||
renderMode = kRenderOther;
|
||||
} else if (screenFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) {
|
||||
renderMode = kRenderToRGBA;
|
||||
} else if (screenFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)) {
|
||||
renderMode = kRenderToABGR;
|
||||
} else {
|
||||
renderMode = kRenderOther;
|
||||
}
|
||||
|
||||
if (renderMode != kRenderDirect && !_screen)
|
||||
_screen = new Graphics::Screen();
|
||||
|
||||
switch (renderMode) {
|
||||
case kRenderToABGR:
|
||||
// ARGB to ABGR
|
||||
copySurface(src, false);
|
||||
break;
|
||||
|
||||
case kRenderToRGBA:
|
||||
// ARGB to RGBA
|
||||
copySurface(src, true);
|
||||
break;
|
||||
|
||||
case kRenderOther: {
|
||||
// Blit the surface to the temporary screen, ignoring the alphas.
|
||||
// This takes care of converting to the screen format
|
||||
Graphics::Surface srcCopy = src;
|
||||
srcCopy.format.aLoss = 8;
|
||||
|
||||
_screen->blitFrom(srcCopy);
|
||||
break;
|
||||
}
|
||||
|
||||
case kRenderDirect:
|
||||
// Blit the virtual surface directly to the screen
|
||||
g_system->copyRectToScreen(src.getPixels(), src.pitch,
|
||||
0, 0, src.w, src.h);
|
||||
g_system->updateScreen();
|
||||
if (srcTransformed) {
|
||||
srcTransformed->free();
|
||||
delete srcTransformed;
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (srcTransformed) {
|
||||
srcTransformed->free();
|
||||
delete srcTransformed;
|
||||
}
|
||||
|
||||
if (_screen)
|
||||
_screen->update();
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::Render(int xoff, int yoff, GraphicFlip flip) {
|
||||
RenderToBackBuffer();
|
||||
Present(xoff, yoff, flip);
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::Render() {
|
||||
Render(0, 0, kFlip_None);
|
||||
}
|
||||
|
||||
Bitmap *ScummVMRendererGraphicsDriver::GetMemoryBackBuffer() {
|
||||
return virtualScreen;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::SetMemoryBackBuffer(Bitmap *backBuffer) {
|
||||
// We need to also test internal AL BITMAP pointer, because we may receive it raw from plugin,
|
||||
// in which case the Bitmap object may be a different wrapper over our own virtual screen.
|
||||
if (backBuffer && (backBuffer->GetAllegroBitmap() != _origVirtualScreen->GetAllegroBitmap())) {
|
||||
virtualScreen = backBuffer;
|
||||
} else {
|
||||
virtualScreen = _origVirtualScreen.get();
|
||||
}
|
||||
_stageVirtualScreen = virtualScreen;
|
||||
|
||||
// Reset old virtual screen's subbitmaps;
|
||||
// NOTE: this MUST NOT be called in the midst of the RenderSpriteBatches!
|
||||
assert(_rendSpriteBatch == UINT32_MAX);
|
||||
if (_rendSpriteBatch != UINT32_MAX)
|
||||
return;
|
||||
for (auto &batch : _spriteBatches) {
|
||||
if (batch.IsParentRegion)
|
||||
batch.Surface.reset();
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap *ScummVMRendererGraphicsDriver::GetStageBackBuffer(bool /*mark_dirty*/) {
|
||||
return _stageVirtualScreen;
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::SetStageBackBuffer(Bitmap *backBuffer) {
|
||||
Bitmap *cur_stage = (_rendSpriteBatch == UINT32_MAX) ? virtualScreen : _spriteBatches[_rendSpriteBatch].Surface.get();
|
||||
// We need to also test internal AL BITMAP pointer, because we may receive it raw from plugin,
|
||||
// in which case the Bitmap object may be a different wrapper over our own virtual screen.
|
||||
if (backBuffer && (backBuffer->GetAllegroBitmap() != cur_stage->GetAllegroBitmap()))
|
||||
_stageVirtualScreen = backBuffer;
|
||||
else
|
||||
_stageVirtualScreen = cur_stage;
|
||||
}
|
||||
|
||||
bool ScummVMRendererGraphicsDriver::GetCopyOfScreenIntoBitmap(Bitmap *destination, const Rect *src_rect, bool at_native_res,
|
||||
GraphicResolution *want_fmt, uint32_t /*batch_skip_filter*/) {
|
||||
(void)at_native_res; // software driver always renders at native resolution at the moment
|
||||
// software filter is taught to copy to any size, so only check color depth
|
||||
if (destination->GetColorDepth() != _srcColorDepth) {
|
||||
if (want_fmt)
|
||||
*want_fmt = GraphicResolution(destination->GetWidth(), destination->GetHeight(), _srcColorDepth);
|
||||
return false;
|
||||
}
|
||||
|
||||
Rect copy_from = src_rect ? *src_rect : _srcRect;
|
||||
if (destination->GetSize() == copy_from.GetSize()) {
|
||||
destination->Blit(virtualScreen, copy_from.Left, copy_from.Top, 0, 0, copy_from.GetWidth(), copy_from.GetHeight());
|
||||
} else {
|
||||
destination->StretchBlt(virtualScreen, copy_from, RectWH(destination->GetSize()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
fade.c - High Color Fading Routines
|
||||
|
||||
Last Revision: 21 June, 2002
|
||||
|
||||
Author: Matthew Leverton
|
||||
**/
|
||||
void ScummVMRendererGraphicsDriver::highcolor_fade_in(Bitmap *vs, void(*draw_callback)(),
|
||||
int speed, int targetColourRed, int targetColourGreen, int targetColourBlue) {
|
||||
Bitmap *bmp_orig = vs;
|
||||
const int col_depth = bmp_orig->GetColorDepth();
|
||||
const int clearColor = makecol_depth(col_depth, targetColourRed, targetColourGreen, targetColourBlue);
|
||||
if (speed <= 0) speed = 16;
|
||||
|
||||
Bitmap *bmp_buff = new Bitmap(bmp_orig->GetWidth(), bmp_orig->GetHeight(), col_depth);
|
||||
SetMemoryBackBuffer(bmp_buff);
|
||||
for (int a = 0; a < 256; a += speed) {
|
||||
bmp_buff->Fill(clearColor);
|
||||
set_trans_blender(0, 0, 0, a);
|
||||
bmp_buff->TransBlendBlt(bmp_orig, 0, 0);
|
||||
|
||||
if (draw_callback)
|
||||
draw_callback();
|
||||
RenderToBackBuffer();
|
||||
Present();
|
||||
|
||||
sys_evt_process_pending();
|
||||
if (_pollingCallback)
|
||||
_pollingCallback();
|
||||
|
||||
WaitForNextFrame();
|
||||
}
|
||||
delete bmp_buff;
|
||||
|
||||
SetMemoryBackBuffer(vs);
|
||||
if (draw_callback)
|
||||
draw_callback();
|
||||
RenderToBackBuffer();
|
||||
Present();
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::highcolor_fade_out(Bitmap *vs, void(*draw_callback)(),
|
||||
int speed, int targetColourRed, int targetColourGreen, int targetColourBlue) {
|
||||
Bitmap *bmp_orig = vs;
|
||||
const int col_depth = vs->GetColorDepth();
|
||||
const int clearColor = makecol_depth(col_depth, targetColourRed, targetColourGreen, targetColourBlue);
|
||||
if (speed <= 0) speed = 16;
|
||||
|
||||
Bitmap *bmp_buff = new Bitmap(bmp_orig->GetWidth(), bmp_orig->GetHeight(), col_depth);
|
||||
SetMemoryBackBuffer(bmp_buff);
|
||||
for (int a = 255 - speed; a > 0; a -= speed) {
|
||||
bmp_buff->Fill(clearColor);
|
||||
set_trans_blender(0, 0, 0, a);
|
||||
bmp_buff->TransBlendBlt(bmp_orig, 0, 0);
|
||||
|
||||
if (draw_callback)
|
||||
draw_callback();
|
||||
RenderToBackBuffer();
|
||||
Present();
|
||||
|
||||
sys_evt_process_pending();
|
||||
if (_pollingCallback)
|
||||
_pollingCallback();
|
||||
|
||||
WaitForNextFrame();
|
||||
}
|
||||
delete bmp_buff;
|
||||
|
||||
SetMemoryBackBuffer(vs);
|
||||
vs->Clear(clearColor);
|
||||
if (draw_callback)
|
||||
draw_callback();
|
||||
RenderToBackBuffer();
|
||||
Present();
|
||||
}
|
||||
/** END FADE.C **/
|
||||
|
||||
// palette fading routiens
|
||||
// from allegro, modified for mp3
|
||||
void initialize_fade_256(int r, int g, int b) {
|
||||
int a;
|
||||
for (a = 0; a < 256; a++) {
|
||||
faded_out_palette[a].r = r / 4;
|
||||
faded_out_palette[a].g = g / 4;
|
||||
faded_out_palette[a].b = b / 4;
|
||||
}
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::__fade_from_range(PALETTE source, PALETTE dest, int speed, int from, int to) {
|
||||
PALETTE temp;
|
||||
int c;
|
||||
|
||||
for (c = 0; c < PAL_SIZE; c++)
|
||||
temp[c] = source[c];
|
||||
|
||||
for (c = 0; c < 64; c += speed) {
|
||||
fade_interpolate(source, dest, temp, c, from, to);
|
||||
set_palette_range(temp, from, to, TRUE);
|
||||
|
||||
RenderToBackBuffer();
|
||||
Present();
|
||||
|
||||
g_system->delayMillis(5);
|
||||
sys_evt_process_pending();
|
||||
if (_pollingCallback)
|
||||
_pollingCallback();
|
||||
WaitForNextFrame();
|
||||
}
|
||||
|
||||
set_palette_range(dest, from, to, TRUE);
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::__fade_out_range(int speed, int from, int to, int targetColourRed, int targetColourGreen, int targetColourBlue) {
|
||||
PALETTE temp;
|
||||
|
||||
initialize_fade_256(targetColourRed, targetColourGreen, targetColourBlue);
|
||||
get_palette(temp);
|
||||
__fade_from_range(temp, faded_out_palette, speed, from, to);
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::FadeOut(int speed, int targetColourRed, int targetColourGreen, int targetColourBlue, uint32_t /*batch_skip_filter*/) {
|
||||
if (_srcColorDepth > 8) {
|
||||
highcolor_fade_out(virtualScreen, _drawPostScreenCallback, speed * 4, targetColourRed, targetColourGreen, targetColourBlue);
|
||||
} else {
|
||||
__fade_out_range(speed, 0, 255, targetColourRed, targetColourGreen, targetColourBlue);
|
||||
}
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::FadeIn(int speed, PALETTE p, int targetColourRed, int targetColourGreen, int targetColourBlue, uint32_t /*batch_skip_filter*/) {
|
||||
if (_drawScreenCallback) {
|
||||
_drawScreenCallback();
|
||||
RenderToBackBuffer();
|
||||
}
|
||||
if (_srcColorDepth > 8) {
|
||||
highcolor_fade_in(virtualScreen, _drawPostScreenCallback, speed * 4, targetColourRed, targetColourGreen, targetColourBlue);
|
||||
} else {
|
||||
initialize_fade_256(targetColourRed, targetColourGreen, targetColourBlue);
|
||||
__fade_from_range(faded_out_palette, p, speed, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
void ScummVMRendererGraphicsDriver::BoxOutEffect(bool blackingOut, int speed, int delay, uint32_t /*batch_skip_filter*/) {
|
||||
if (blackingOut) {
|
||||
int yspeed = _srcRect.GetHeight() / (_srcRect.GetWidth() / speed);
|
||||
int boxwid = speed, boxhit = yspeed;
|
||||
Bitmap *bmp_orig = virtualScreen;
|
||||
Bitmap *bmp_buff = new Bitmap(bmp_orig->GetWidth(), bmp_orig->GetHeight(), bmp_orig->GetColorDepth());
|
||||
SetMemoryBackBuffer(bmp_buff);
|
||||
|
||||
while (boxwid < _srcRect.GetWidth()) {
|
||||
boxwid += speed;
|
||||
boxhit += yspeed;
|
||||
int vcentre = _srcRect.GetHeight() / 2;
|
||||
bmp_orig->FillRect(Rect(_srcRect.GetWidth() / 2 - boxwid / 2, vcentre - boxhit / 2,
|
||||
_srcRect.GetWidth() / 2 + boxwid / 2, vcentre + boxhit / 2), 0);
|
||||
bmp_buff->Fill(0);
|
||||
bmp_buff->Blit(bmp_orig);
|
||||
|
||||
if (_drawPostScreenCallback)
|
||||
_drawPostScreenCallback();
|
||||
RenderToBackBuffer();
|
||||
Present();
|
||||
|
||||
sys_evt_process_pending();
|
||||
if (_pollingCallback)
|
||||
_pollingCallback();
|
||||
|
||||
_G(platform)->Delay(delay);
|
||||
}
|
||||
delete bmp_buff;
|
||||
SetMemoryBackBuffer(bmp_orig);
|
||||
} else {
|
||||
error("BoxOut fade-in not implemented in sw gfx driver");
|
||||
}
|
||||
}
|
||||
// end fading routines
|
||||
|
||||
|
||||
ScummVMRendererGraphicsFactory *ScummVMRendererGraphicsFactory::_factory = nullptr;
|
||||
|
||||
ScummVMRendererGraphicsFactory::~ScummVMRendererGraphicsFactory() {
|
||||
_factory = nullptr;
|
||||
}
|
||||
|
||||
size_t ScummVMRendererGraphicsFactory::GetFilterCount() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const GfxFilterInfo *ScummVMRendererGraphicsFactory::GetFilterInfo(size_t index) const {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return _G(scummvmGfxFilter);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
String ScummVMRendererGraphicsFactory::GetDefaultFilterID() const {
|
||||
return _GP(scummvmGfxFilter).Id;
|
||||
}
|
||||
|
||||
/* static */ ScummVMRendererGraphicsFactory *ScummVMRendererGraphicsFactory::GetFactory() {
|
||||
if (!_factory)
|
||||
_factory = new ScummVMRendererGraphicsFactory();
|
||||
return _factory;
|
||||
}
|
||||
|
||||
ScummVMRendererGraphicsDriver *ScummVMRendererGraphicsFactory::EnsureDriverCreated() {
|
||||
if (!_driver)
|
||||
_driver = new ScummVMRendererGraphicsDriver();
|
||||
return _driver;
|
||||
}
|
||||
|
||||
ScummVMRendererGfxFilter *ScummVMRendererGraphicsFactory::CreateFilter(const String &id) {
|
||||
if (_GP(scummvmGfxFilter).Id.CompareNoCase(id) == 0)
|
||||
return new ScummVMRendererGfxFilter();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace ALSW
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
330
engines/ags/engine/gfx/ali_3d_scummvm.h
Normal file
330
engines/ags/engine/gfx/ali_3d_scummvm.h
Normal file
@@ -0,0 +1,330 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Software graphics factory, draws raw bitmaps onto a virtual screen,
|
||||
// converts to SDL_Texture and finally presents with SDL_Renderer.
|
||||
//
|
||||
// TODO: replace nearest-neighbour software filter with SDL's own accelerated
|
||||
// scaling, maybe add more filter types if SDL renderer supports them.
|
||||
// Only keep Hqx filter as a software option (might need to change how the
|
||||
// filter code works).
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_ALI_3D_SCUMMVM_H
|
||||
#define AGS_ENGINE_GFX_ALI_3D_SCUMMVM_H
|
||||
|
||||
#include "common/std/memory.h"
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/engine/gfx/ddb.h"
|
||||
#include "ags/engine/gfx/gfx_driver_factory_base.h"
|
||||
#include "ags/engine/gfx/gfx_driver_base.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
namespace ALSW {
|
||||
|
||||
class ScummVMRendererGraphicsDriver;
|
||||
class ScummVMRendererGfxFilter;
|
||||
using AGS::Shared::Bitmap;
|
||||
|
||||
enum RendererFlip {
|
||||
FLIP_NONE = 0x00000000, /**< Do not flip */
|
||||
FLIP_HORIZONTAL = 0x00000001, /**< flip horizontally */
|
||||
FLIP_VERTICAL = 0x00000002 /**< flip vertically */
|
||||
};
|
||||
|
||||
class ALSoftwareBitmap : public BaseDDB {
|
||||
public:
|
||||
uint32_t GetRefID() const override { return UINT32_MAX /* not supported */; }
|
||||
|
||||
int GetAlpha() const override {
|
||||
return _alpha;
|
||||
}
|
||||
void SetAlpha(int alpha) override {
|
||||
_alpha = alpha;
|
||||
}
|
||||
void SetFlippedLeftRight(bool isFlipped) override {
|
||||
_flipped = isFlipped;
|
||||
}
|
||||
void SetStretch(int width, int height, bool /*useResampler*/) override {
|
||||
_stretchToWidth = width;
|
||||
_stretchToHeight = height;
|
||||
}
|
||||
void SetLightLevel(int /*lightLevel*/) override {}
|
||||
void SetTint(int /*red*/, int /*green*/, int /*blue*/, int /*tintSaturation*/) override {}
|
||||
|
||||
Bitmap *_bmp = nullptr;
|
||||
bool _flipped = false;
|
||||
int _stretchToWidth = 0, _stretchToHeight = 0;
|
||||
int _alpha = 255;
|
||||
|
||||
ALSoftwareBitmap(int width, int height, int color_depth, bool opaque) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
_colDepth = color_depth;
|
||||
_opaque = opaque;
|
||||
_stretchToWidth = _width;
|
||||
_stretchToHeight = _height;
|
||||
}
|
||||
|
||||
ALSoftwareBitmap(Bitmap *bmp, bool has_alpha, bool opaque) {
|
||||
_bmp = bmp;
|
||||
_width = bmp->GetWidth();
|
||||
_height = bmp->GetHeight();
|
||||
_colDepth = bmp->GetColorDepth();
|
||||
_opaque = opaque;
|
||||
_hasAlpha = has_alpha;
|
||||
_stretchToWidth = _width;
|
||||
_stretchToHeight = _height;
|
||||
}
|
||||
|
||||
int GetWidthToRender() {
|
||||
return _stretchToWidth;
|
||||
}
|
||||
int GetHeightToRender() {
|
||||
return _stretchToHeight;
|
||||
}
|
||||
|
||||
~ALSoftwareBitmap() override = default;
|
||||
};
|
||||
|
||||
|
||||
class ScummVMRendererGfxModeList : public IGfxModeList {
|
||||
public:
|
||||
ScummVMRendererGfxModeList(const std::vector<DisplayMode> &modes)
|
||||
: _modes(modes) {
|
||||
}
|
||||
|
||||
int GetModeCount() const override {
|
||||
return _modes.size();
|
||||
}
|
||||
|
||||
bool GetMode(int index, DisplayMode &mode) const override {
|
||||
if (index >= 0 && (size_t)index < _modes.size()) {
|
||||
mode = _modes[index];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<DisplayMode> _modes;
|
||||
};
|
||||
|
||||
|
||||
typedef SpriteDrawListEntry<ALSoftwareBitmap> ALDrawListEntry;
|
||||
// Software renderer's sprite batch
|
||||
struct ALSpriteBatch {
|
||||
uint32_t ID = 0u;
|
||||
// Clipping viewport, also used as a destination for blitting optional Surface;
|
||||
// in *relative* coordinates to parent surface.
|
||||
Rect Viewport;
|
||||
// Optional model transformation, to be applied to each sprite
|
||||
SpriteTransform Transform;
|
||||
// Intermediate surface which will be drawn upon and transformed if necessary
|
||||
std::shared_ptr<Bitmap> Surface;
|
||||
// Whether surface is a parent surface's region (e.g. virtual screen)
|
||||
bool IsParentRegion = false;
|
||||
// Tells whether the surface is treated as opaque or transparent
|
||||
bool Opaque = false;
|
||||
};
|
||||
typedef std::vector<ALSpriteBatch> ALSpriteBatches;
|
||||
|
||||
|
||||
class ScummVMRendererGraphicsDriver : public GraphicsDriverBase {
|
||||
public:
|
||||
ScummVMRendererGraphicsDriver();
|
||||
~ScummVMRendererGraphicsDriver() override;
|
||||
|
||||
const char *GetDriverID() override {
|
||||
return "Software";
|
||||
}
|
||||
|
||||
bool RequiresFullRedrawEachFrame() override { return false; }
|
||||
bool HasAcceleratedTransform() override { return false; }
|
||||
bool UsesMemoryBackBuffer() override { return true; }
|
||||
bool ShouldReleaseRenderTargets() override { return false; }
|
||||
|
||||
const char *GetDriverName() override {
|
||||
return "ScummVM 2D renderer";
|
||||
}
|
||||
|
||||
void SetTintMethod(TintMethod /*method*/) override;
|
||||
bool SetDisplayMode(const DisplayMode &mode) override;
|
||||
void UpdateDeviceScreen(const Size &screen_sz) override;
|
||||
bool SetNativeResolution(const GraphicResolution &native_res) override;
|
||||
bool SetRenderFrame(const Rect &dst_rect) override;
|
||||
bool IsModeSupported(const DisplayMode &mode) override;
|
||||
int GetDisplayDepthForNativeDepth(int native_color_depth) const override;
|
||||
IGfxModeList *GetSupportedModeList(int color_depth) override;
|
||||
PGfxFilter GetGraphicsFilter() const override;
|
||||
void UnInit();
|
||||
// Clears the screen rectangle. The coordinates are expected in the **native game resolution**.
|
||||
void ClearRectangle(int x1, int y1, int x2, int y2, RGB *colorToUse) override;
|
||||
int GetCompatibleBitmapFormat(int color_depth) override;
|
||||
size_t GetAvailableTextureMemory() override {
|
||||
// not using textures for sprites anyway
|
||||
return 0;
|
||||
}
|
||||
IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque) override;
|
||||
IDriverDependantBitmap *CreateDDBFromBitmap(Bitmap *bitmap, bool has_alpha, bool opaque) override;
|
||||
IDriverDependantBitmap *CreateRenderTargetDDB(int width, int height, int color_depth, bool opaque) override;
|
||||
void UpdateDDBFromBitmap(IDriverDependantBitmap *ddb, Bitmap *bitmap, bool has_alpha) override;
|
||||
void DestroyDDB(IDriverDependantBitmap *ddb) override;
|
||||
|
||||
IDriverDependantBitmap *GetSharedDDB(uint32_t /*sprite_id*/,
|
||||
Bitmap *bitmap, bool has_alpha, bool opaque) override {
|
||||
// Software renderer does not require a texture cache, because it uses bitmaps directly
|
||||
return CreateDDBFromBitmap(bitmap, has_alpha, opaque);
|
||||
}
|
||||
|
||||
void UpdateSharedDDB(uint32_t /*sprite_id*/, Bitmap */*bitmap*/, bool /*has_alpha*/, bool /*opaque*/) override {
|
||||
/* do nothing */
|
||||
}
|
||||
void ClearSharedDDB(uint32_t /*sprite_id*/) override {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
void DrawSprite(int x, int y, IDriverDependantBitmap *ddb) override;
|
||||
void SetScreenFade(int red, int green, int blue) override;
|
||||
void SetScreenTint(int red, int green, int blue) override;
|
||||
void SetStageScreen(const Size &sz, int x = 0, int y = 0) override;
|
||||
|
||||
void RenderToBackBuffer() override;
|
||||
void Render() override;
|
||||
void Render(int xoff, int yoff, Shared::GraphicFlip flip) override;
|
||||
bool GetCopyOfScreenIntoBitmap(Bitmap *destination, const Rect *src_rect, bool at_native_res, GraphicResolution *want_fmt,
|
||||
uint32_t batch_skip_filter = 0u) override;
|
||||
void FadeOut(int speed, int targetColourRed, int targetColourGreen, int targetColourBlue,
|
||||
uint32_t batch_skip_filter = 0u) override;
|
||||
void FadeIn(int speed, PALETTE pal, int targetColourRed, int targetColourGreen, int targetColourBlue,
|
||||
uint32_t batch_skip_filter = 0u) override;
|
||||
void BoxOutEffect(bool blackingOut, int speed, int delay, uint32_t batch_skip_filter = 0u) override;
|
||||
bool SupportsGammaControl() override;
|
||||
void SetGamma(int newGamma) override;
|
||||
void UseSmoothScaling(bool /*enabled*/) override {}
|
||||
bool DoesSupportVsyncToggle() override;
|
||||
void RenderSpritesAtScreenResolution(bool /*enabled*/) override {}
|
||||
Bitmap *GetMemoryBackBuffer() override;
|
||||
void SetMemoryBackBuffer(Bitmap *backBuffer) override;
|
||||
Bitmap *GetStageBackBuffer(bool mark_dirty) override;
|
||||
void SetStageBackBuffer(Bitmap *backBuffer) override;
|
||||
bool GetStageMatrixes(RenderMatrixes & /*rm*/) override {
|
||||
return false; /* not supported */
|
||||
}
|
||||
|
||||
typedef std::shared_ptr<ScummVMRendererGfxFilter> PSDLRenderFilter;
|
||||
|
||||
void SetGraphicsFilter(PSDLRenderFilter filter);
|
||||
|
||||
protected:
|
||||
bool SetVsyncImpl(bool vsync, bool &vsync_res) override;
|
||||
size_t GetLastDrawEntryIndex() override {
|
||||
return _spriteList.size();
|
||||
}
|
||||
|
||||
private:
|
||||
Graphics::Screen *_screen = nullptr;
|
||||
PSDLRenderFilter _filter;
|
||||
|
||||
bool _hasGamma = false;
|
||||
#ifdef TODO
|
||||
uint16 _defaultGammaRed[256] {};
|
||||
uint16 _defaultGammaGreen[256] {};
|
||||
uint16 _defaultGammaBlue[256] {};
|
||||
int _gamma = 100;
|
||||
#endif
|
||||
|
||||
/* SDL_Renderer *_renderer = nullptr;
|
||||
SDL_Texture *_screenTex = nullptr; */
|
||||
// BITMAP struct for wrapping screen texture locked pixels, so that we may use blit()
|
||||
BITMAP *_fakeTexBitmap = nullptr;
|
||||
unsigned char *_lastTexPixels = nullptr;
|
||||
int _lastTexPitch = -1;
|
||||
|
||||
// Original virtual screen created and managed by the renderer.
|
||||
std::unique_ptr<Bitmap> _origVirtualScreen;
|
||||
// Current virtual screen bitmap; may be either pointing to _origVirtualScreen,
|
||||
// or provided by external user (for example - plugin).
|
||||
// Its pixels are copied to the video texture to be presented by SDL_Renderer.
|
||||
Bitmap *virtualScreen;
|
||||
// Stage screen meant for particular rendering stages, may be referencing
|
||||
// actual virtual screen or separate bitmap of different size that is
|
||||
// blitted to virtual screen at the stage finalization.
|
||||
Bitmap *_stageVirtualScreen;
|
||||
int _tint_red, _tint_green, _tint_blue;
|
||||
|
||||
// Sprite batches (parent scene nodes)
|
||||
ALSpriteBatches _spriteBatches;
|
||||
// List of sprites to render
|
||||
std::vector<ALDrawListEntry> _spriteList;
|
||||
|
||||
void InitSpriteBatch(size_t index, const SpriteBatchDesc &desc) override;
|
||||
void ResetAllBatches() override;
|
||||
|
||||
// Use gfx filter to create a new virtual screen
|
||||
void CreateVirtualScreen();
|
||||
void DestroyVirtualScreen();
|
||||
// Unset parameters and release resources related to the display mode
|
||||
void ReleaseDisplayMode();
|
||||
// Renders single sprite batch on the precreated surface
|
||||
size_t RenderSpriteBatch(const ALSpriteBatch &batch, size_t from, Shared::Bitmap *surface, int surf_offx, int surf_offy);
|
||||
|
||||
void highcolor_fade_in(Bitmap *vs, void(*draw_callback)(), int speed, int targetColourRed, int targetColourGreen, int targetColourBlue);
|
||||
void highcolor_fade_out(Bitmap *vs, void(*draw_callback)(), int speed, int targetColourRed, int targetColourGreen, int targetColourBlue);
|
||||
void __fade_from_range(PALETTE source, PALETTE dest, int speed, int from, int to);
|
||||
void __fade_out_range(int speed, int from, int to, int targetColourRed, int targetColourGreen, int targetColourBlue);
|
||||
// Copy raw screen bitmap pixels to the screen
|
||||
void copySurface(const Graphics::Surface &src, bool mode);
|
||||
// Render bitmap on screen
|
||||
void Present(int xoff = 0, int yoff = 0, Shared::GraphicFlip flip = Shared::kFlip_None);
|
||||
};
|
||||
|
||||
|
||||
class ScummVMRendererGraphicsFactory : public GfxDriverFactoryBase<ScummVMRendererGraphicsDriver, ScummVMRendererGfxFilter> {
|
||||
public:
|
||||
~ScummVMRendererGraphicsFactory() override;
|
||||
|
||||
size_t GetFilterCount() const override;
|
||||
const GfxFilterInfo *GetFilterInfo(size_t index) const override;
|
||||
String GetDefaultFilterID() const override;
|
||||
|
||||
static ScummVMRendererGraphicsFactory *GetFactory();
|
||||
|
||||
private:
|
||||
ScummVMRendererGraphicsDriver *EnsureDriverCreated() override;
|
||||
ScummVMRendererGfxFilter *CreateFilter(const String &id) override;
|
||||
|
||||
static ScummVMRendererGraphicsFactory *_factory;
|
||||
};
|
||||
|
||||
} // namespace ALSW
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
51
engines/ags/engine/gfx/blender.cpp
Normal file
51
engines/ags/engine/gfx/blender.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/engine/gfx/blender.h"
|
||||
#include "ags/lib/allegro.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
void set_my_trans_blender(int r, int g, int b, int a) {
|
||||
// use standard allegro 15 and 16 bit blenders, but customize
|
||||
// the 32-bit one to preserve the alpha channel
|
||||
set_blender_mode(kAlphaPreservedBlenderMode, r, g, b, a);
|
||||
}
|
||||
|
||||
void set_additive_alpha_blender() {
|
||||
set_blender_mode(kAdditiveBlenderMode, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void set_argb2argb_blender(int alpha) {
|
||||
set_blender_mode(kArgbToArgbBlender, 0, 0, 0, alpha);
|
||||
}
|
||||
|
||||
void set_opaque_alpha_blender() {
|
||||
set_blender_mode(kOpaqueBlenderMode, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void set_argb2any_blender() {
|
||||
// TODO: Properly implement this new mode
|
||||
set_blender_mode(kArgbToArgbBlender, 0, 0, 0, 0xff);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
58
engines/ags/engine/gfx/blender.h
Normal file
58
engines/ags/engine/gfx/blender.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// AGS specific color blending routines for transparency and tinting effects
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_BLENDER_H
|
||||
#define AGS_ENGINE_GFX_BLENDER_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
//
|
||||
// Allegro's standard alpha blenders result in:
|
||||
// - src and dst RGB are combined proportionally to src alpha
|
||||
// (src.rgb * src.alpha + dst.rgb * (1 - dst.alpha));
|
||||
// - final alpha is zero.
|
||||
// This blender is suggested for use with opaque destinations
|
||||
// (ones without alpha channel).
|
||||
//
|
||||
/* Declared in Allegro's color.h:
|
||||
void set_alpha_blender();
|
||||
*/
|
||||
|
||||
// Customizable alpha blender that uses the supplied alpha value as src alpha,
|
||||
// and preserves destination's alpha channel (if there was one);
|
||||
void set_my_trans_blender(int r, int g, int b, int a);
|
||||
// Additive alpha blender plain copies src over, applying a summ of src and
|
||||
// dst alpha values.
|
||||
void set_additive_alpha_blender();
|
||||
// Opaque alpha blender plain copies src over, applying opaque alpha value.
|
||||
void set_opaque_alpha_blender();
|
||||
// Sets argb2argb for 32-bit mode, and provides appropriate funcs for blending 32-bit onto 15/16/24-bit destination
|
||||
void set_argb2any_blender();
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
66
engines/ags/engine/gfx/color_engine.cpp
Normal file
66
engines/ags/engine/gfx/color_engine.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Implementation from wgt2allg.cpp specific to Engine runtime
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "ags/lib/allegro.h"
|
||||
#include "ags/shared/util/wgt2_allg.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
void __my_setcolor(int *ctset, int newcol, int wantColDep) {
|
||||
if (wantColDep == 8)
|
||||
ctset[0] = newcol;
|
||||
else if (newcol & 0x40000000) // already calculated it
|
||||
ctset[0] = newcol;
|
||||
else if ((newcol >= 32) && (wantColDep > 16)) {
|
||||
// true-color
|
||||
#ifdef SWAP_RB_HICOL_FOR_32to24_32
|
||||
ctset[0] = makeacol32(getb16(newcol), getg16(newcol), getr16(newcol), 255);
|
||||
#else
|
||||
ctset[0] = makeacol32(getr16(newcol), getg16(newcol), getb16(newcol), 255);
|
||||
#endif
|
||||
} else if (newcol >= 32) {
|
||||
|
||||
// If it's 15-bit, convert the color
|
||||
if (wantColDep == 15)
|
||||
ctset[0] = (newcol & 0x001f) | ((newcol >> 1) & 0x7fe0);
|
||||
else
|
||||
ctset[0] = newcol;
|
||||
} else {
|
||||
ctset[0] = makecol_depth(wantColDep, col_lookups[newcol] >> 16,
|
||||
(col_lookups[newcol] >> 8) & 0x000ff, col_lookups[newcol] & 0x000ff);
|
||||
|
||||
// in case it's used on an alpha-channel sprite, make sure it's visible
|
||||
if (wantColDep > 16)
|
||||
ctset[0] |= 0xff000000;
|
||||
}
|
||||
|
||||
// if it's 32-bit color, signify that the colour has been calculated
|
||||
//if (wantColDep >= 24)
|
||||
// ctset[0] |= 0x40000000;
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
65
engines/ags/engine/gfx/ddb.h
Normal file
65
engines/ags/engine/gfx/ddb.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Driver-dependant bitmap interface.
|
||||
//
|
||||
// This interface describes an individual sprite object. The actual texture
|
||||
// data (pixel data) may be shared among multiple DDBs, while DDB define
|
||||
// additional settings telling how to present the texture: transform, colorize,
|
||||
// and so on.
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_DDB_H
|
||||
#define AGS_ENGINE_GFX_DDB_H
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
class IDriverDependantBitmap {
|
||||
public:
|
||||
// Get an arbitrary sprite ID, returns UINT32_MAX if does not have one
|
||||
virtual uint32_t GetRefID() const = 0;
|
||||
|
||||
virtual int GetAlpha() const = 0;
|
||||
virtual void SetAlpha(int alpha) = 0; // 0-255
|
||||
virtual void SetFlippedLeftRight(bool isFlipped) = 0;
|
||||
virtual void SetStretch(int width, int height, bool useResampler = true) = 0;
|
||||
virtual void SetLightLevel(int light_level) = 0; // 0-255
|
||||
virtual void SetTint(int red, int green, int blue, int tintSaturation) = 0; // 0-255
|
||||
|
||||
virtual int GetWidth() const = 0;
|
||||
virtual int GetHeight() const = 0;
|
||||
virtual int GetColorDepth() const = 0;
|
||||
virtual bool MatchesFormat(AGS::Shared::Bitmap *other) const = 0;
|
||||
|
||||
protected:
|
||||
IDriverDependantBitmap() {}
|
||||
virtual ~IDriverDependantBitmap() {}
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
87
engines/ags/engine/gfx/gfx_defines.h
Normal file
87
engines/ags/engine/gfx/gfx_defines.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_GFX_DEFINES_H
|
||||
#define AGS_ENGINE_GFX_GFX_DEFINES_H
|
||||
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/shared/util/geometry.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
// GraphicResolution struct determines image size and color depth
|
||||
struct GraphicResolution : Size {
|
||||
int32_t ColorDepth; // color depth in bits per pixel
|
||||
|
||||
GraphicResolution()
|
||||
: ColorDepth(0) {
|
||||
}
|
||||
|
||||
GraphicResolution(int32_t width, int32_t height, int32_t color_depth)
|
||||
: Size(width, height), ColorDepth(color_depth) {
|
||||
}
|
||||
|
||||
GraphicResolution(Size size, int32_t color_depth)
|
||||
: Size(size), ColorDepth(color_depth) {
|
||||
}
|
||||
|
||||
inline bool IsValid() const {
|
||||
return Width > 0 && Height > 0 && ColorDepth > 0;
|
||||
}
|
||||
};
|
||||
|
||||
enum WindowMode {
|
||||
kWnd_Windowed, // regular resizable window with a border and a caption
|
||||
kWnd_Fullscreen, // real (aka exclusive) fullscreen mode
|
||||
kWnd_FullDesktop // borderless window filling whole desktop
|
||||
};
|
||||
|
||||
// DisplayMode struct provides extended description of display mode
|
||||
struct DisplayMode : public GraphicResolution {
|
||||
int32_t RefreshRate = 0;
|
||||
bool Vsync = false;
|
||||
WindowMode Mode = kWnd_Windowed;
|
||||
|
||||
// Tells if this is logically a normal windowed mode
|
||||
inline bool IsWindowed() const {
|
||||
return Mode == kWnd_Windowed;
|
||||
}
|
||||
// Tells if this mode defines a real fullscreen, which would require gfx driver to support it
|
||||
inline bool IsRealFullscreen() const {
|
||||
return Mode == kWnd_Fullscreen;
|
||||
}
|
||||
|
||||
DisplayMode() = default;
|
||||
DisplayMode(const GraphicResolution & res, WindowMode mode = kWnd_Windowed, int32_t refresh = 0, bool vsync = false)
|
||||
: GraphicResolution(res)
|
||||
, RefreshRate(refresh)
|
||||
, Vsync(vsync)
|
||||
, Mode(mode) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
567
engines/ags/engine/gfx/gfx_driver_base.cpp
Normal file
567
engines/ags/engine/gfx/gfx_driver_base.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/engine/gfx/gfxfilter.h"
|
||||
#include "ags/engine/gfx/gfx_driver_base.h"
|
||||
#include "ags/engine/gfx/gfx_util.h"
|
||||
#include "ags/shared/debugging/out.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
GraphicsDriverBase::GraphicsDriverBase()
|
||||
: _pollingCallback(nullptr)
|
||||
, _drawScreenCallback(nullptr)
|
||||
, _spriteEvtCallback(nullptr)
|
||||
, _initGfxCallback(nullptr) {
|
||||
_actSpriteBatch = UINT32_MAX;
|
||||
_rendSpriteBatch = UINT32_MAX;
|
||||
}
|
||||
|
||||
bool GraphicsDriverBase::IsModeSet() const {
|
||||
return _mode.Width != 0 && _mode.Height != 0 && _mode.ColorDepth != 0;
|
||||
}
|
||||
|
||||
bool GraphicsDriverBase::IsNativeSizeValid() const {
|
||||
return !_srcRect.IsEmpty();
|
||||
}
|
||||
|
||||
bool GraphicsDriverBase::IsRenderFrameValid() const {
|
||||
return !_srcRect.IsEmpty() && !_dstRect.IsEmpty();
|
||||
}
|
||||
|
||||
DisplayMode GraphicsDriverBase::GetDisplayMode() const {
|
||||
return _mode;
|
||||
}
|
||||
|
||||
Size GraphicsDriverBase::GetNativeSize() const {
|
||||
return _srcRect.GetSize();
|
||||
}
|
||||
|
||||
Rect GraphicsDriverBase::GetRenderDestination() const {
|
||||
return _dstRect;
|
||||
}
|
||||
|
||||
bool GraphicsDriverBase::SetVsync(bool enabled) {
|
||||
if (!_capsVsync || (_mode.Vsync == enabled)) {
|
||||
return _mode.Vsync;
|
||||
}
|
||||
|
||||
bool new_value = true;
|
||||
if (SetVsyncImpl(enabled, new_value) && new_value == enabled) {
|
||||
Debug::Printf("SetVsync: switched to %d", new_value);
|
||||
_mode.Vsync = new_value;
|
||||
}
|
||||
else {
|
||||
Debug::Printf("SetVsync: failed, stay at %d", _mode.Vsync);
|
||||
_capsVsync = false; // mark as non-capable (at least in current mode)
|
||||
}
|
||||
return _mode.Vsync;
|
||||
}
|
||||
|
||||
bool GraphicsDriverBase::GetVsync() const {
|
||||
return _mode.Vsync;
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::BeginSpriteBatch(const Rect &viewport, const SpriteTransform &transform,
|
||||
GraphicFlip flip, PBitmap surface, uint32_t filter_flags) {
|
||||
_spriteBatchDesc.push_back(SpriteBatchDesc(_actSpriteBatch, viewport, transform, flip, surface, filter_flags));
|
||||
_spriteBatchRange.push_back(std::make_pair(GetLastDrawEntryIndex(), (size_t) SIZE_MAX));
|
||||
_actSpriteBatch = _spriteBatchDesc.size() - 1;
|
||||
InitSpriteBatch(_actSpriteBatch, _spriteBatchDesc[_actSpriteBatch]);
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::EndSpriteBatch() {
|
||||
assert(_actSpriteBatch != UINT32_MAX);
|
||||
if (_actSpriteBatch == UINT32_MAX)
|
||||
return;
|
||||
_spriteBatchRange[_actSpriteBatch].second = GetLastDrawEntryIndex();
|
||||
_actSpriteBatch = _spriteBatchDesc[_actSpriteBatch].Parent;
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::ClearDrawLists() {
|
||||
ResetAllBatches();
|
||||
_actSpriteBatch = UINT32_MAX;
|
||||
_spriteBatchDesc.clear();
|
||||
_spriteBatchRange.clear();
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::OnInit() {
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::OnUnInit() {
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::OnModeSet(const DisplayMode &mode) {
|
||||
_mode = mode;
|
||||
// Adjust some generic parameters as necessary
|
||||
_mode.Vsync &= _capsVsync;
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::OnModeReleased() {
|
||||
_mode = DisplayMode();
|
||||
_dstRect = Rect();
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::OnScalingChanged() {
|
||||
PGfxFilter filter = GetGraphicsFilter();
|
||||
if (filter)
|
||||
_filterRect = filter->SetTranslation(_srcRect.GetSize(), _dstRect);
|
||||
else
|
||||
_filterRect = Rect();
|
||||
_scaling.Init(_srcRect.GetSize(), _dstRect);
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::OnSetNativeRes(const GraphicResolution &native_res) {
|
||||
_srcRect = RectWH(0, 0, native_res.Width, native_res.Height);
|
||||
_srcColorDepth = native_res.ColorDepth;
|
||||
OnScalingChanged();
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::OnSetRenderFrame(const Rect &dst_rect) {
|
||||
_dstRect = dst_rect;
|
||||
OnScalingChanged();
|
||||
}
|
||||
|
||||
void GraphicsDriverBase::OnSetFilter() {
|
||||
_filterRect = GetGraphicsFilter()->SetTranslation(Size(_srcRect.GetSize()), _dstRect);
|
||||
}
|
||||
|
||||
|
||||
VideoMemoryGraphicsDriver::VideoMemoryGraphicsDriver()
|
||||
: _stageVirtualScreenDDB(nullptr)
|
||||
, _stageScreenDirty(false)
|
||||
, _fxIndex(0) {
|
||||
// Only to have something meaningful as default
|
||||
_vmem_a_shift_32 = 24;
|
||||
_vmem_r_shift_32 = 16;
|
||||
_vmem_g_shift_32 = 8;
|
||||
_vmem_b_shift_32 = 0;
|
||||
}
|
||||
|
||||
VideoMemoryGraphicsDriver::~VideoMemoryGraphicsDriver() {
|
||||
DestroyAllStageScreens();
|
||||
}
|
||||
|
||||
Bitmap *VideoMemoryGraphicsDriver::GetMemoryBackBuffer() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::SetMemoryBackBuffer(Bitmap * /*backBuffer*/) {
|
||||
// do nothing, video-memory drivers don't use main back buffer, only stage bitmaps they pass to plugins
|
||||
}
|
||||
|
||||
Bitmap *VideoMemoryGraphicsDriver::GetStageBackBuffer(bool mark_dirty) {
|
||||
if (_rendSpriteBatch == UINT32_MAX)
|
||||
return nullptr;
|
||||
_stageScreenDirty |= mark_dirty;
|
||||
return GetStageScreenRaw(_rendSpriteBatch);
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::SetStageBackBuffer(Bitmap *backBuffer) {
|
||||
// do nothing, video-memory drivers don't support this
|
||||
}
|
||||
|
||||
bool VideoMemoryGraphicsDriver::GetStageMatrixes(RenderMatrixes &rm) {
|
||||
rm = _stageMatrixes;
|
||||
return true;
|
||||
}
|
||||
|
||||
IDriverDependantBitmap *VideoMemoryGraphicsDriver::CreateDDBFromBitmap(Bitmap *bitmap, bool has_alpha, bool opaque) {
|
||||
IDriverDependantBitmap * ddb = CreateDDB(bitmap->GetWidth(), bitmap->GetHeight(), bitmap->GetColorDepth(), opaque);
|
||||
if (ddb)
|
||||
UpdateDDBFromBitmap(ddb, bitmap, has_alpha);
|
||||
return ddb;
|
||||
}
|
||||
|
||||
IDriverDependantBitmap *VideoMemoryGraphicsDriver::GetSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool has_alpha, bool opaque) {
|
||||
const auto found = _txRefs.find(sprite_id);
|
||||
if (found != _txRefs.end()) {
|
||||
const auto &item = found->_value;
|
||||
if (!item.Data.expired())
|
||||
return CreateDDB(item.Data.lock(), item.Res.Width, item.Res.Height, item.Res.ColorDepth, opaque);
|
||||
}
|
||||
|
||||
// Create and add a new element
|
||||
std::shared_ptr<TextureData> txdata(CreateTextureData(bitmap->GetWidth(), bitmap->GetHeight(), opaque));
|
||||
txdata->ID = sprite_id;
|
||||
UpdateTextureData(txdata.get(), bitmap, has_alpha, opaque);
|
||||
// only add into the map when has valid sprite ID
|
||||
if (sprite_id != UINT32_MAX) {
|
||||
_txRefs[sprite_id] = TextureCacheItem(txdata,
|
||||
GraphicResolution(bitmap->GetWidth(), bitmap->GetHeight(), bitmap->GetColorDepth()));
|
||||
}
|
||||
return CreateDDB(txdata, bitmap->GetWidth(), bitmap->GetHeight(), bitmap->GetColorDepth(), opaque);
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::UpdateSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool has_alpha, bool opaque) {
|
||||
const auto found = _txRefs.find(sprite_id);
|
||||
if (found == _txRefs.end())
|
||||
return;
|
||||
auto txdata = found->_value.Data.lock();
|
||||
if (!txdata)
|
||||
return;
|
||||
|
||||
// Update texture ONLY if the bitmap's resolution matches;
|
||||
// otherwise - detach shared texture (don't delete the data yet, as it may be in use)
|
||||
const auto &res = found->_value.Res;
|
||||
if (res.Width == bitmap->GetWidth() && res.Height == bitmap->GetHeight() && res.ColorDepth == bitmap->GetColorDepth()) {
|
||||
UpdateTextureData(txdata.get(), bitmap, has_alpha, opaque);
|
||||
} else {
|
||||
txdata->ID = UINT32_MAX;
|
||||
_txRefs.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::ClearSharedDDB(uint32_t sprite_id) {
|
||||
// Reset sprite ID for any remaining shared txdata,
|
||||
// then remove the reference from the cache;
|
||||
// NOTE: we do not delete txdata itself, as it may be temporarily in use
|
||||
const auto found = _txRefs.find(sprite_id);
|
||||
if (found != _txRefs.end()) {
|
||||
auto txdata = found->_value.Data.lock();
|
||||
if (txdata)
|
||||
txdata->ID = UINT32_MAX;
|
||||
_txRefs.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::DestroyDDB(IDriverDependantBitmap* ddb) {
|
||||
uint32_t sprite_id = ddb->GetRefID();
|
||||
DestroyDDBImpl(ddb);
|
||||
// Remove shared object from ref list if no more active refs left
|
||||
const auto found = _txRefs.find(sprite_id);
|
||||
if (found != _txRefs.end() && found->_value.Data.expired())
|
||||
_txRefs.erase(found);
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::SetStageScreen(const Size &sz, int x, int y) {
|
||||
SetStageScreen(_actSpriteBatch, sz, x, y);
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::SetStageScreen(size_t index, const Size &sz, int x, int y) {
|
||||
if (_stageScreens.size() <= index)
|
||||
_stageScreens.resize(index + 1);
|
||||
_stageScreens[index].Position = RectWH(x, y, sz.Width, sz.Height);
|
||||
}
|
||||
|
||||
Bitmap *VideoMemoryGraphicsDriver::GetStageScreenRaw(size_t index) {
|
||||
assert(index < _stageScreens.size());
|
||||
if (_stageScreens.size() <= index)
|
||||
return nullptr;
|
||||
|
||||
auto &scr = _stageScreens[index];
|
||||
const Size sz = scr.Position.GetSize();
|
||||
if (scr.Raw && (scr.Raw->GetSize() != sz)) {
|
||||
scr.Raw.reset();
|
||||
if (scr.DDB)
|
||||
DestroyDDB(scr.DDB);
|
||||
scr.DDB = nullptr;
|
||||
}
|
||||
if (!scr.Raw && !sz.IsNull()) {
|
||||
scr.Raw.reset(new Bitmap(sz.Width, sz.Height, _mode.ColorDepth));
|
||||
scr.DDB = CreateDDB(sz.Width, sz.Height, _mode.ColorDepth, false);
|
||||
}
|
||||
return scr.Raw.get();
|
||||
}
|
||||
|
||||
IDriverDependantBitmap *VideoMemoryGraphicsDriver::UpdateStageScreenDDB(size_t index, int &x, int &y) {
|
||||
assert((index < _stageScreens.size()) && _stageScreens[index].DDB);
|
||||
if ((_stageScreens.size() <= index) || !_stageScreens[index].Raw || !_stageScreens[index].DDB)
|
||||
return nullptr;
|
||||
|
||||
auto &scr = _stageScreens[index];
|
||||
UpdateDDBFromBitmap(scr.DDB, scr.Raw.get(), true);
|
||||
scr.Raw->ClearTransparent();
|
||||
x = scr.Position.Left;
|
||||
y = scr.Position.Top;
|
||||
return scr.DDB;
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::DestroyAllStageScreens() {
|
||||
if (_stageVirtualScreenDDB) // FIXME: Not in upstream
|
||||
this->DestroyDDB(_stageVirtualScreenDDB);
|
||||
_stageVirtualScreenDDB = nullptr;
|
||||
|
||||
for (size_t i = 0; i < _stageScreens.size(); ++i) {
|
||||
if (_stageScreens[i].DDB)
|
||||
DestroyDDB(_stageScreens[i].DDB);
|
||||
}
|
||||
_stageScreens.clear();
|
||||
}
|
||||
|
||||
IDriverDependantBitmap *VideoMemoryGraphicsDriver::DoSpriteEvtCallback(int evt, int data, int &x, int &y) {
|
||||
if (!_spriteEvtCallback)
|
||||
error("Unhandled attempt to draw null sprite");
|
||||
_stageScreenDirty = false;
|
||||
// NOTE: this is not clear whether return value of callback may be
|
||||
// relied on. Existing plugins do not seem to return anything but 0,
|
||||
// even if they handle this event. This is why we also set
|
||||
// _stageScreenDirty in certain plugin API function implementations.
|
||||
_stageScreenDirty |= _spriteEvtCallback(evt, data) != 0;
|
||||
if (_stageScreenDirty) {
|
||||
return UpdateStageScreenDDB(_rendSpriteBatch, x, y);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDriverDependantBitmap *VideoMemoryGraphicsDriver::MakeFx(int r, int g, int b) {
|
||||
if (_fxIndex == _fxPool.size()) _fxPool.push_back(ScreenFx());
|
||||
ScreenFx &fx = _fxPool[_fxIndex];
|
||||
if (fx.DDB == nullptr) {
|
||||
fx.Raw = BitmapHelper::CreateBitmap(16, 16, _mode.ColorDepth);
|
||||
fx.DDB = CreateDDBFromBitmap(fx.Raw, false, true);
|
||||
}
|
||||
if (r != fx.Red || g != fx.Green || b != fx.Blue) {
|
||||
fx.Raw->Clear(makecol_depth(fx.Raw->GetColorDepth(), r, g, b));
|
||||
this->UpdateDDBFromBitmap(fx.DDB, fx.Raw, false);
|
||||
fx.Red = r;
|
||||
fx.Green = g;
|
||||
fx.Blue = b;
|
||||
}
|
||||
_fxIndex++;
|
||||
return fx.DDB;
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::ResetFxPool() {
|
||||
_fxIndex = 0;
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::DestroyFxPool() {
|
||||
for (auto &fx : _fxPool) {
|
||||
if (fx.DDB)
|
||||
DestroyDDB(fx.DDB);
|
||||
delete fx.Raw;
|
||||
}
|
||||
_fxPool.clear();
|
||||
_fxIndex = 0;
|
||||
}
|
||||
|
||||
template <typename T> T algetr(const T);
|
||||
template <typename T> T algetg(const T);
|
||||
template <typename T> T algetb(const T);
|
||||
template <typename T> T algeta(const T);
|
||||
|
||||
template <> uint8_t algetr(const uint8_t c) { return getr8(c); }
|
||||
template <> uint8_t algetg(const uint8_t c) { return getg8(c); }
|
||||
template <> uint8_t algetb(const uint8_t c) { return getb8(c); }
|
||||
template <> uint8_t algeta(const uint8_t c) { return 0xFF; }
|
||||
|
||||
template <> uint16_t algetr(const uint16_t c) { return getr16(c); }
|
||||
template <> uint16_t algetg(const uint16_t c) { return getg16(c); }
|
||||
template <> uint16_t algetb(const uint16_t c) { return getb16(c); }
|
||||
template <> uint16_t algeta(const uint16_t c) { return 0xFF; }
|
||||
|
||||
template <> uint32_t algetr(const uint32_t c) { return getr32(c); }
|
||||
template <> uint32_t algetg(const uint32_t c) { return getg32(c); }
|
||||
template <> uint32_t algetb(const uint32_t c) { return getb32(c); }
|
||||
template <> uint32_t algeta(const uint32_t c) { return geta32(c); }
|
||||
|
||||
template <typename T> bool is_color_mask(const T);
|
||||
template <> bool is_color_mask(const uint8_t c) { return c == MASK_COLOR_8;}
|
||||
template <> bool is_color_mask(const uint16_t c) { return c == MASK_COLOR_16;}
|
||||
template <> bool is_color_mask(const uint32_t c) { return c == MASK_COLOR_32;}
|
||||
|
||||
template <typename T> void get_pixel_if_not_transparent(const T *pixel, T *red, T *green, T *blue, T *divisor) {
|
||||
const T px_color = pixel[0];
|
||||
if (!is_color_mask<T>(px_color)) {
|
||||
*red += algetr<T>(px_color);
|
||||
*green += algetg<T>(px_color);
|
||||
*blue += algetb<T>(px_color);
|
||||
divisor[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
#define VMEMCOLOR_RGBA(r,g,b,a) \
|
||||
( (((a) & 0xFF) << _vmem_a_shift_32) | (((r) & 0xFF) << _vmem_r_shift_32) | (((g) & 0xFF) << _vmem_g_shift_32) | (((b) & 0xFF) << _vmem_b_shift_32) )
|
||||
|
||||
// Template helper function which converts bitmap to a video memory buffer,
|
||||
// applies transparency and optionally copies the source alpha channel (if available).
|
||||
template<typename T, bool HasAlpha>
|
||||
void VideoMemoryGraphicsDriver::BitmapToVideoMemImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch) {
|
||||
// tell the compiler these won't change mid loop execution
|
||||
const int t_width = tile->width;
|
||||
const int t_height = tile->height;
|
||||
const int t_x = tile->x;
|
||||
const int t_y = tile->y;
|
||||
|
||||
const int idst_pitch = dst_pitch * sizeof(uint8_t) / sizeof(uint32_t); // destination is always 32-bit
|
||||
auto idst = reinterpret_cast<uint32_t *>(dst_ptr);
|
||||
|
||||
for (int y = 0; y < t_height; y++) {
|
||||
const uint8_t *scanline_at = bitmap->GetScanLine(y + t_y);
|
||||
for (int x = 0; x < t_width; x++) {
|
||||
auto srcData = (const T *)&scanline_at[(x + t_x) * sizeof(T)];
|
||||
const T src_color = srcData[0];
|
||||
if (HasAlpha) {
|
||||
idst[x] = VMEMCOLOR_RGBA(algetr<T>(src_color), algetg<T>(src_color), algetb<T>(src_color), algeta<T>(src_color));
|
||||
} else if (is_color_mask<T>(src_color)) {
|
||||
idst[x] = 0;
|
||||
} else {
|
||||
idst[x] = VMEMCOLOR_RGBA(algetr<T>(src_color), algetg<T>(src_color), algetb<T>(src_color), 0xFF);
|
||||
}
|
||||
}
|
||||
idst += idst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Template helper function which converts bitmap to a video memory buffer,
|
||||
// assuming that the destination is always opaque (alpha channel is filled with 0xFF)
|
||||
template<typename T>
|
||||
void VideoMemoryGraphicsDriver::BitmapToVideoMemOpaqueImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch) {
|
||||
// tell the compiler these won't change mid loop execution
|
||||
const int t_width = tile->width;
|
||||
const int t_height = tile->height;
|
||||
const int t_x = tile->x;
|
||||
const int t_y = tile->y;
|
||||
|
||||
const int idst_pitch = dst_pitch * sizeof(uint8_t) / sizeof(uint32_t); // destination is always 32-bit
|
||||
auto idst = reinterpret_cast<uint32_t *>(dst_ptr);
|
||||
|
||||
for (int y = 0; y < t_height; y++) {
|
||||
const uint8_t *scanline_at = bitmap->GetScanLine(y + t_y);
|
||||
for (int x = 0; x < t_width; x++) {
|
||||
auto srcData = (const T *)&scanline_at[(x + t_x) * sizeof(T)];
|
||||
const T src_color = srcData[0];
|
||||
idst[x] = VMEMCOLOR_RGBA(algetr<T>(src_color), algetg<T>(src_color), algetb<T>(src_color), 0xFF);
|
||||
}
|
||||
idst += idst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Template helper function which converts bitmap to a video memory buffer
|
||||
// with a semi-transparent pixels fix for "Linear" graphics filter which prevents
|
||||
// colored outline (usually either of black or "magic pink" color).
|
||||
template<typename T, bool HasAlpha>
|
||||
void VideoMemoryGraphicsDriver::BitmapToVideoMemLinearImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch) {
|
||||
// tell the compiler these won't change mid loop execution
|
||||
const int t_width = tile->width;
|
||||
const int t_height = tile->height;
|
||||
const int t_x = tile->x;
|
||||
const int t_y = tile->y;
|
||||
|
||||
const int src_bpp = sizeof(T);
|
||||
const int idst_pitch = dst_pitch * sizeof(uint8_t) / sizeof(uint32_t); // destination is always 32-bit
|
||||
auto idst = reinterpret_cast<uint32_t *>(dst_ptr);
|
||||
bool lastPixelWasTransparent = false;
|
||||
for (int y = 0; y < t_height; y++) {
|
||||
lastPixelWasTransparent = false;
|
||||
const uint8_t *scanline_before = (y > 0) ? bitmap->GetScanLine(y + t_y - 1) : nullptr;
|
||||
const uint8_t *scanline_at = bitmap->GetScanLine(y + t_y);
|
||||
const uint8_t *scanline_after = (y < t_height - 1) ? bitmap->GetScanLine(y + t_y + 1) : nullptr;
|
||||
for (int x = 0; x < t_width; x++) {
|
||||
auto srcData = (const T *)&scanline_at[(x + t_x) * src_bpp];
|
||||
const T src_color = srcData[0];
|
||||
|
||||
if (is_color_mask<T>(src_color)) {
|
||||
// set to transparent, but use the colour from the neighbouring
|
||||
// pixel to stop the linear filter doing colored outlines
|
||||
T red = 0, green = 0, blue = 0, divisor = 0;
|
||||
if (x > 0)
|
||||
get_pixel_if_not_transparent<T>(&srcData[-1], &red, &green, &blue, &divisor);
|
||||
if (x < t_width - 1)
|
||||
get_pixel_if_not_transparent<T>(&srcData[1], &red, &green, &blue, &divisor);
|
||||
if (y > 0)
|
||||
get_pixel_if_not_transparent<T>((const T *)&scanline_before[(x + t_x) * src_bpp], &red, &green, &blue, &divisor);
|
||||
if (y < t_height - 1)
|
||||
get_pixel_if_not_transparent<T>((const T *)&scanline_after[(x + t_x) * src_bpp], &red, &green, &blue, &divisor);
|
||||
if (divisor > 0)
|
||||
idst[x] = VMEMCOLOR_RGBA(red / divisor, green / divisor, blue / divisor, 0);
|
||||
else
|
||||
idst[x] = 0;
|
||||
lastPixelWasTransparent = true;
|
||||
} else if (HasAlpha) {
|
||||
idst[x] = VMEMCOLOR_RGBA(algetr<T>(src_color), algetg<T>(src_color), algetb<T>(src_color), algeta<T>(src_color));
|
||||
} else {
|
||||
idst[x] = VMEMCOLOR_RGBA(algetr<T>(src_color), algetg<T>(src_color), algetb<T>(src_color), 0xFF);
|
||||
if (lastPixelWasTransparent) {
|
||||
// update the colour of the previous transparent pixel, to
|
||||
// stop colored outlines when linear filtering
|
||||
idst[x - 1] = idst[x] & 0x00FFFFFF;
|
||||
lastPixelWasTransparent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
idst += idst_pitch;
|
||||
}
|
||||
}
|
||||
void VideoMemoryGraphicsDriver::BitmapToVideoMem(const Bitmap *bitmap, const bool has_alpha, const TextureTile *tile,
|
||||
uint8_t *dst_ptr, const int dst_pitch, const bool usingLinearFiltering) {
|
||||
switch (bitmap->GetColorDepth()) {
|
||||
case 8:
|
||||
if (usingLinearFiltering) {
|
||||
BitmapToVideoMemLinearImpl<uint8_t, false>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
} else {
|
||||
BitmapToVideoMemImpl<uint8_t, false>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
}
|
||||
|
||||
break;
|
||||
case 16:
|
||||
if (usingLinearFiltering) {
|
||||
BitmapToVideoMemLinearImpl<uint16_t, false>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
} else {
|
||||
BitmapToVideoMemImpl<uint16_t, false>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
if (usingLinearFiltering) {
|
||||
if (has_alpha) {
|
||||
BitmapToVideoMemLinearImpl<uint32_t, true>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
} else {
|
||||
BitmapToVideoMemLinearImpl<uint32_t, false>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
}
|
||||
} else {
|
||||
if (has_alpha) {
|
||||
BitmapToVideoMemImpl<uint32_t, true>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
} else {
|
||||
BitmapToVideoMemImpl<uint32_t, false>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoMemoryGraphicsDriver::BitmapToVideoMemOpaque(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch) {
|
||||
switch (bitmap->GetColorDepth()) {
|
||||
case 8:
|
||||
BitmapToVideoMemOpaqueImpl<uint8_t>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
break;
|
||||
case 16:
|
||||
BitmapToVideoMemOpaqueImpl<uint16_t>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
break;
|
||||
case 32:
|
||||
BitmapToVideoMemOpaqueImpl<uint32_t>(bitmap, tile, dst_ptr, dst_pitch);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
394
engines/ags/engine/gfx/gfx_driver_base.h
Normal file
394
engines/ags/engine/gfx/gfx_driver_base.h
Normal file
@@ -0,0 +1,394 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Implementation base for graphics driver
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_GFX_DRIVER_BASE_H
|
||||
#define AGS_ENGINE_GFX_GFX_DRIVER_BASE_H
|
||||
|
||||
#include "common/std/memory.h"
|
||||
#include "common/std/map.h"
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/engine/gfx/ddb.h"
|
||||
#include "ags/shared/gfx/gfx_def.h"
|
||||
#include "ags/engine/gfx/graphics_driver.h"
|
||||
#include "ags/shared/util/scaling.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
using Shared::Bitmap;
|
||||
using Shared::PlaneScaling;
|
||||
|
||||
// Sprite batch, defines viewport and an optional model transformation for the list of sprites
|
||||
struct SpriteBatchDesc {
|
||||
uint32_t Parent = UINT32_MAX;
|
||||
// View rectangle for positioning and clipping, in resolution coordinates
|
||||
// (this may be screen or game frame resolution, depending on circumstances)
|
||||
Rect Viewport;
|
||||
// Optional model transformation, to be applied to each sprite
|
||||
SpriteTransform Transform;
|
||||
// Optional flip, applied to the whole batch as the last transform
|
||||
Shared::GraphicFlip Flip = Shared::kFlip_None;
|
||||
// Optional bitmap to draw sprites upon. Used exclusively by the software rendering mode.
|
||||
PBitmap Surface;
|
||||
// Optional filter flags; this lets to filter certain batches out during some operations,
|
||||
// such as fading effects or making screenshots.
|
||||
uint32_t FilterFlags = 0u;
|
||||
|
||||
SpriteBatchDesc() = default;
|
||||
SpriteBatchDesc(uint32_t parent, const Rect viewport, const SpriteTransform & transform,
|
||||
Shared::GraphicFlip flip = Shared::kFlip_None, PBitmap surface = nullptr, uint32_t filter_flags = 0)
|
||||
: Parent(parent)
|
||||
, Viewport(viewport)
|
||||
, Transform(transform)
|
||||
, Flip(flip)
|
||||
, Surface(surface)
|
||||
, FilterFlags(filter_flags) {
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<SpriteBatchDesc> SpriteBatchDescs;
|
||||
|
||||
// The single sprite entry in the render list
|
||||
template<class T_DDB>
|
||||
struct SpriteDrawListEntry {
|
||||
T_DDB *ddb = nullptr; // TODO: use shared pointer?
|
||||
uint32_t node = 0; // sprite batch / scene node index
|
||||
int x = 0, y = 0; // sprite position, in local batch / node coordinates
|
||||
bool skip = false;
|
||||
|
||||
SpriteDrawListEntry() = default;
|
||||
SpriteDrawListEntry(T_DDB * ddb_, uint32_t node_, int x_, int y_)
|
||||
: ddb(ddb_)
|
||||
, node(node_)
|
||||
, x(x_)
|
||||
, y(y_)
|
||||
, skip(false) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// GraphicsDriverBase - is the parent class for all graphics drivers in AGS,
|
||||
// that incapsulates the most common functionality.
|
||||
class GraphicsDriverBase : public IGraphicsDriver {
|
||||
public:
|
||||
GraphicsDriverBase();
|
||||
|
||||
bool IsModeSet() const override;
|
||||
bool IsNativeSizeValid() const override;
|
||||
bool IsRenderFrameValid() const override;
|
||||
DisplayMode GetDisplayMode() const override;
|
||||
Size GetNativeSize() const override;
|
||||
Rect GetRenderDestination() const override;
|
||||
|
||||
bool SetVsync(bool enabled) override;
|
||||
bool GetVsync() const override;
|
||||
|
||||
void BeginSpriteBatch(const Rect &viewport, const SpriteTransform &transform,
|
||||
Shared::GraphicFlip flip = Shared::kFlip_None, PBitmap surface = nullptr,
|
||||
uint32_t filter_flags = 0) override;
|
||||
void EndSpriteBatch() override;
|
||||
void ClearDrawLists() override;
|
||||
|
||||
void SetCallbackForPolling(GFXDRV_CLIENTCALLBACK callback) override {
|
||||
_pollingCallback = callback;
|
||||
}
|
||||
void SetCallbackToDrawScreen(GFXDRV_CLIENTCALLBACK callback, GFXDRV_CLIENTCALLBACK post_callback) override {
|
||||
_drawScreenCallback = callback;
|
||||
_drawPostScreenCallback = post_callback;
|
||||
}
|
||||
void SetCallbackOnInit(GFXDRV_CLIENTCALLBACKINITGFX callback) override {
|
||||
_initGfxCallback = callback;
|
||||
}
|
||||
void SetCallbackOnSpriteEvt(GFXDRV_CLIENTCALLBACKEVT callback) override {
|
||||
_spriteEvtCallback = callback;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Special internal values, applied to DrawListEntry
|
||||
static const uintptr_t DRAWENTRY_STAGECALLBACK = 0x0;
|
||||
static const uintptr_t DRAWENTRY_FADE = 0x1;
|
||||
static const uintptr_t DRAWENTRY_TINT = 0x2;
|
||||
|
||||
// Called after graphics driver was initialized for use for the first time
|
||||
virtual void OnInit();
|
||||
// Called just before graphics mode is going to be uninitialized and its
|
||||
// resources released
|
||||
virtual void OnUnInit();
|
||||
// Called after new mode was successfully initialized
|
||||
virtual void OnModeSet(const DisplayMode &mode);
|
||||
// Called when the new native size is set
|
||||
virtual void OnSetNativeRes(const GraphicResolution &native_res);
|
||||
// Called before display mode is going to be released
|
||||
virtual void OnModeReleased();
|
||||
// Called when new render frame is set
|
||||
virtual void OnSetRenderFrame(const Rect &dst_rect);
|
||||
// Called when the new filter is set
|
||||
virtual void OnSetFilter();
|
||||
|
||||
// Try changing vsync setting; fills new current mode in vsync_res,
|
||||
// returns whether the new setting was set successfully.
|
||||
virtual bool SetVsyncImpl(bool vsync, bool &vsync_res) { return false; }
|
||||
|
||||
// Initialize sprite batch and allocate necessary resources
|
||||
virtual void InitSpriteBatch(size_t index, const SpriteBatchDesc &desc) = 0;
|
||||
// Gets the index of a last draw entry (sprite)
|
||||
virtual size_t GetLastDrawEntryIndex() = 0;
|
||||
// Clears sprite lists
|
||||
virtual void ResetAllBatches() = 0;
|
||||
|
||||
void OnScalingChanged();
|
||||
|
||||
DisplayMode _mode; // display mode settings
|
||||
Rect _srcRect; // rendering source rect
|
||||
int _srcColorDepth; // rendering source color depth (in bits per pixel)
|
||||
Rect _dstRect; // rendering destination rect
|
||||
Rect _filterRect; // filter scaling destination rect (before final scaling)
|
||||
PlaneScaling _scaling; // native -> render dest coordinate transformation
|
||||
|
||||
// Capability flags
|
||||
bool _capsVsync = false; // is vsync available
|
||||
|
||||
// Callbacks
|
||||
GFXDRV_CLIENTCALLBACK _pollingCallback;
|
||||
GFXDRV_CLIENTCALLBACK _drawScreenCallback;
|
||||
GFXDRV_CLIENTCALLBACK _drawPostScreenCallback;
|
||||
GFXDRV_CLIENTCALLBACKEVT _spriteEvtCallback;
|
||||
GFXDRV_CLIENTCALLBACKINITGFX _initGfxCallback;
|
||||
|
||||
// Sprite batch parameters
|
||||
SpriteBatchDescs _spriteBatchDesc;
|
||||
// The range of sprites in this sprite batch (counting nested sprites):
|
||||
// the index of a first of the current batch, and the next index past the last one.
|
||||
std::vector<std::pair<size_t, size_t>> _spriteBatchRange;
|
||||
// The index of a currently filled sprite batch
|
||||
size_t _actSpriteBatch;
|
||||
// The index of a currently rendered sprite batch
|
||||
// (or -1 / UINT32_MAX if we are outside of the render pass)
|
||||
uint32_t _rendSpriteBatch;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Parent class for the video memory DDBs
|
||||
class BaseDDB : public IDriverDependantBitmap {
|
||||
public:
|
||||
int GetWidth() const override {
|
||||
return _width;
|
||||
}
|
||||
int GetHeight() const override {
|
||||
return _height;
|
||||
}
|
||||
int GetColorDepth() const override {
|
||||
return _colDepth;
|
||||
}
|
||||
bool MatchesFormat(AGS::Shared::Bitmap *other) const {
|
||||
return _width == other->GetWidth() && _height == other->GetHeight() && _colDepth == other->GetColorDepth();
|
||||
}
|
||||
|
||||
int _width = 0, _height = 0;
|
||||
int _colDepth = 0;
|
||||
bool _hasAlpha = false; // has meaningful alpha channel
|
||||
bool _opaque = false; // no mask color
|
||||
|
||||
protected:
|
||||
BaseDDB() {}
|
||||
virtual ~BaseDDB() {}
|
||||
};
|
||||
|
||||
// A base parent for the otherwise opaque texture data object;
|
||||
// TextureData refers to the pixel data itself, with no additional
|
||||
// properties. It may be shared between multiple sprites if necessary.
|
||||
struct TextureData {
|
||||
uint32_t ID = UINT32_MAX;
|
||||
bool RenderTarget = false; // replace with flags later
|
||||
virtual ~TextureData() = default;
|
||||
protected:
|
||||
TextureData() = default;
|
||||
};
|
||||
|
||||
// Generic TextureTile base
|
||||
struct TextureTile {
|
||||
int x = 0, y = 0;
|
||||
int width = 0, height = 0;
|
||||
// allocWidth and allocHeight tell the actual allocated texture size
|
||||
int allocWidth = 0, allocHeight = 0;
|
||||
};
|
||||
|
||||
|
||||
// VideoMemoryGraphicsDriver - is the parent class for the graphic drivers
|
||||
// which drawing method is based on passing the sprite stack into GPU,
|
||||
// rather than blitting to flat screen bitmap.
|
||||
class VideoMemoryGraphicsDriver : public GraphicsDriverBase {
|
||||
public:
|
||||
VideoMemoryGraphicsDriver();
|
||||
~VideoMemoryGraphicsDriver() override;
|
||||
|
||||
bool RequiresFullRedrawEachFrame() override { return true; }
|
||||
bool HasAcceleratedTransform() override { return true; }
|
||||
// NOTE: although we do use ours, we do not let engine draw upon it;
|
||||
// only plugin handling are allowed to request our mem buffer
|
||||
// for compatibility reasons.
|
||||
bool UsesMemoryBackBuffer() override { return false; }
|
||||
|
||||
Bitmap *GetMemoryBackBuffer() override;
|
||||
void SetMemoryBackBuffer(Bitmap *backBuffer) override;
|
||||
Bitmap *GetStageBackBuffer(bool mark_dirty) override;
|
||||
void SetStageBackBuffer(Bitmap *backBuffer) override;
|
||||
bool GetStageMatrixes(RenderMatrixes &rm) override;
|
||||
// Creates new texture using given parameters
|
||||
IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque) override = 0;
|
||||
// Creates new texture and copy bitmap contents over
|
||||
IDriverDependantBitmap *CreateDDBFromBitmap(Bitmap *bitmap, bool has_alpha, bool opaque = false) override;
|
||||
// Get shared texture from cache, or create from bitmap and assign ID
|
||||
IDriverDependantBitmap *GetSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool has_alpha, bool opaque) override;
|
||||
// Removes the shared texture reference, will force the texture to recreate next time
|
||||
void ClearSharedDDB(uint32_t sprite_id) override;
|
||||
// Updates shared texture data, but only if it is present in the cache
|
||||
void UpdateSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool has_alpha, bool opaque) override;
|
||||
void DestroyDDB(IDriverDependantBitmap* ddb) override;
|
||||
|
||||
// Sets stage screen parameters for the current batch.
|
||||
void SetStageScreen(const Size &sz, int x = 0, int y = 0) override;
|
||||
|
||||
protected:
|
||||
// Create texture data with the given parameters
|
||||
virtual TextureData *CreateTextureData(int width, int height, bool opaque, bool as_render_target = false) = 0;
|
||||
// Update texture data from the given bitmap
|
||||
virtual void UpdateTextureData(TextureData *txdata, Bitmap *bmp, bool has_alpha, bool opaque) = 0;
|
||||
// Create DDB using preexisting texture data
|
||||
virtual IDriverDependantBitmap *CreateDDB(std::shared_ptr<TextureData> txdata,
|
||||
int width, int height, int color_depth, bool opaque) = 0;
|
||||
// Retrieve shared texture data object from the given DDB
|
||||
virtual std::shared_ptr<TextureData> GetTextureData(IDriverDependantBitmap *ddb) = 0;
|
||||
virtual void DestroyDDBImpl(IDriverDependantBitmap* ddb) = 0;
|
||||
|
||||
// Stage screens are raw bitmap buffers meant to be sent to plugins on demand
|
||||
// at certain drawing stages. If used at least once these buffers are then
|
||||
// rendered as additional sprites in their respected order.
|
||||
// Presets a stage screen with the given position (size is obligatory, offsets not).
|
||||
void SetStageScreen(size_t index, const Size &sz, int x = 0, int y = 0);
|
||||
// Returns a raw bitmap for the given stage screen.
|
||||
Bitmap *GetStageScreenRaw(size_t index);
|
||||
// Updates and returns a DDB for the given stage screen, and optional x,y position;
|
||||
// clears the raw bitmap after copying to the texture.
|
||||
IDriverDependantBitmap *UpdateStageScreenDDB(size_t index, int &x, int &y);
|
||||
// Disposes all the stage screen raw bitmaps and DDBs.
|
||||
void DestroyAllStageScreens();
|
||||
// Use engine callback to pass a render event;
|
||||
// returns a DDB if anything was drawn onto the current stage screen
|
||||
// (in which case it also fills optional x,y position),
|
||||
// or nullptr if this entry should be skipped.
|
||||
IDriverDependantBitmap *DoSpriteEvtCallback(int evt, int data, int &x, int &y);
|
||||
|
||||
// Prepare and get fx item from the pool
|
||||
IDriverDependantBitmap *MakeFx(int r, int g, int b);
|
||||
// Resets fx pool counter
|
||||
void ResetFxPool();
|
||||
// Disposes all items in the fx pool
|
||||
void DestroyFxPool();
|
||||
|
||||
// Prepares bitmap to be applied to the texture, copies pixels to the provided buffer
|
||||
void BitmapToVideoMem(const Bitmap *bitmap, const bool has_alpha, const TextureTile *tile,
|
||||
uint8_t *dst_ptr, const int dst_pitch, const bool usingLinearFiltering);
|
||||
// Same but optimized for opaque source bitmaps which ignore transparent "mask color"
|
||||
void BitmapToVideoMemOpaque(const Bitmap *bitmap, const TextureTile *tile,
|
||||
uint8_t *dst_ptr, const int dst_pitch);
|
||||
|
||||
// Stage virtual screen is used to let plugins draw custom graphics
|
||||
// in between render stages (between room and GUI, after GUI, and so on)
|
||||
PBitmap _stageVirtualScreen;
|
||||
IDriverDependantBitmap *_stageVirtualScreenDDB;
|
||||
// Stage matrixes are used to let plugins with hardware acceleration know model matrix;
|
||||
// these matrixes are filled compatible with each given renderer
|
||||
RenderMatrixes _stageMatrixes;
|
||||
|
||||
// Color component shifts in video bitmap format (set by implementations)
|
||||
int _vmem_a_shift_32;
|
||||
int _vmem_r_shift_32;
|
||||
int _vmem_g_shift_32;
|
||||
int _vmem_b_shift_32;
|
||||
|
||||
private:
|
||||
// Stage virtual screens are used to let plugins draw custom graphics
|
||||
// in between render stages (between room and GUI, after GUI, and so on).
|
||||
// TODO: possibly may be optimized further by having only 1 bitmap/ddb
|
||||
// pair, and subbitmaps for raw drawing on separate stages.
|
||||
struct StageScreen {
|
||||
Rect Position; // bitmap size and pos preset (bitmap may be created later)
|
||||
std::unique_ptr<Bitmap> Raw;
|
||||
IDriverDependantBitmap *DDB = nullptr;
|
||||
};
|
||||
std::vector<StageScreen> _stageScreens;
|
||||
// Flag which indicates whether stage screen was drawn upon during engine
|
||||
// callback and has to be inserted into sprite stack.
|
||||
bool _stageScreenDirty;
|
||||
|
||||
// Fx quads pool (for screen overlay effects)
|
||||
struct ScreenFx {
|
||||
Bitmap *Raw = nullptr;
|
||||
IDriverDependantBitmap *DDB = nullptr;
|
||||
int Red = -1;
|
||||
int Green = -1;
|
||||
int Blue = -1;
|
||||
};
|
||||
std::vector<ScreenFx> _fxPool;
|
||||
size_t _fxIndex; // next free pool item
|
||||
|
||||
// specialized method to convert bitmap to video memory depending on bit depth
|
||||
template<typename T, bool HasAlpha>
|
||||
void BitmapToVideoMemImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch);
|
||||
|
||||
template<typename T>
|
||||
void BitmapToVideoMemOpaqueImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch);
|
||||
|
||||
template<typename T, bool HasAlpha>
|
||||
void BitmapToVideoMemLinearImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch);
|
||||
|
||||
// Texture short-term cache:
|
||||
// - caches textures while they are in the immediate use;
|
||||
// - this lets to share same texture data among multiple sprites on screen.
|
||||
// TextureCacheItem stores weak references to the existing texture tiles,
|
||||
// identified by an arbitrary uint32 number.
|
||||
// TODO: a curious topic to consider: reuse released TextureData for
|
||||
// textures of the same size (research potential performance impact).
|
||||
struct TextureCacheItem {
|
||||
GraphicResolution Res;
|
||||
std::weak_ptr<TextureData> Data;
|
||||
TextureCacheItem() = default;
|
||||
TextureCacheItem(std::shared_ptr<TextureData> data, const GraphicResolution &res)
|
||||
: Data(data), Res(res) {}
|
||||
};
|
||||
std::unordered_map<uint32_t, TextureCacheItem> _txRefs;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
45
engines/ags/engine/gfx/gfx_driver_factory.cpp
Normal file
45
engines/ags/engine/gfx/gfx_driver_factory.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/textconsole.h"
|
||||
#include "ags/engine/gfx/gfxfilter_scummvm_renderer.h"
|
||||
#include "ags/engine/gfx/gfx_driver_factory.h"
|
||||
#include "ags/engine/gfx/ali_3d_scummvm.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
void GetGfxDriverFactoryNames(StringV &ids) {
|
||||
ids.push_back("ScummVM");
|
||||
}
|
||||
|
||||
IGfxDriverFactory *GetGfxDriverFactory(const String id) {
|
||||
if (id.CompareNoCase("ScummVM") == 0)
|
||||
return ALSW::ScummVMRendererGraphicsFactory::GetFactory();
|
||||
|
||||
error("No graphics factory with such id: %s", id.GetCStr());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
86
engines/ags/engine/gfx/gfx_driver_factory.h
Normal file
86
engines/ags/engine/gfx/gfx_driver_factory.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Graphics driver factory interface
|
||||
//
|
||||
// Graphics factory is supposed to be singleton. Factory implementation must
|
||||
// guarantee that it may be created and destroyed any number of times during
|
||||
// program execution.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_GFX_DRIVER_FACTORY_H
|
||||
#define AGS_ENGINE_GFX_GFX_DRIVER_FACTORY_H
|
||||
|
||||
#include "common/std/memory.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
#include "ags/shared/util/string_types.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
using Shared::String;
|
||||
using Shared::StringV;
|
||||
class IGraphicsDriver;
|
||||
class IGfxFilter;
|
||||
struct GfxFilterInfo;
|
||||
typedef std::shared_ptr<IGfxFilter> PGfxFilter;
|
||||
|
||||
|
||||
class IGfxDriverFactory {
|
||||
public:
|
||||
virtual ~IGfxDriverFactory() {
|
||||
}
|
||||
|
||||
// Shutdown graphics factory and deallocate any resources it owns;
|
||||
// graphics factory will be unusable after calling this function.
|
||||
virtual void Shutdown() = 0;
|
||||
// Get graphics driver associated with this factory; creates one if
|
||||
// it does not exist.
|
||||
virtual IGraphicsDriver *GetDriver() = 0;
|
||||
// Destroy graphics driver associated with this factory; does nothing
|
||||
// if one was not created yet,
|
||||
virtual void DestroyDriver() = 0;
|
||||
|
||||
// Get number of supported filters
|
||||
virtual size_t GetFilterCount() const = 0;
|
||||
// Get filter description
|
||||
virtual const GfxFilterInfo *GetFilterInfo(size_t index) const = 0;
|
||||
// Get ID of the default filter
|
||||
virtual String GetDefaultFilterID() const = 0;
|
||||
|
||||
// Assign specified filter to graphics driver
|
||||
virtual PGfxFilter SetFilter(const String &id, String &filter_error) = 0;
|
||||
};
|
||||
|
||||
// Query the available graphics factory names
|
||||
void GetGfxDriverFactoryNames(StringV &ids);
|
||||
// Acquire the graphics factory singleton object by its id
|
||||
IGfxDriverFactory *GetGfxDriverFactory(const String id);
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
108
engines/ags/engine/gfx/gfx_driver_factory_base.h
Normal file
108
engines/ags/engine/gfx/gfx_driver_factory_base.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Base implementation of IGfxDriverFactory
|
||||
//
|
||||
// GfxDriverFactoryBase is a template implementation of basic driver factory
|
||||
// functionality, such as creating and destruction of graphics driver, and
|
||||
// managing graphic filters.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_GFX_DRIVER_FACTORY_BASE_H
|
||||
#define AGS_ENGINE_GFX_GFX_DRIVER_FACTORY_BASE_H
|
||||
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/engine/gfx/gfx_driver_factory.h"
|
||||
#include "ags/engine/gfx/gfxfilter.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
template <class TGfxDriverClass, class TGfxFilterClass>
|
||||
class GfxDriverFactoryBase : public IGfxDriverFactory {
|
||||
protected:
|
||||
~GfxDriverFactoryBase() override {
|
||||
delete _driver;
|
||||
}
|
||||
|
||||
public:
|
||||
void Shutdown() override {
|
||||
delete this;
|
||||
}
|
||||
|
||||
IGraphicsDriver *GetDriver() override {
|
||||
if (!_driver)
|
||||
_driver = EnsureDriverCreated();
|
||||
return _driver;
|
||||
}
|
||||
|
||||
void DestroyDriver() override {
|
||||
delete _driver;
|
||||
_driver = nullptr;
|
||||
}
|
||||
|
||||
PGfxFilter SetFilter(const String &id, String &filter_error) override {
|
||||
TGfxDriverClass *driver = EnsureDriverCreated();
|
||||
if (!driver) {
|
||||
filter_error = "Graphics driver was not created";
|
||||
return PGfxFilter();
|
||||
}
|
||||
|
||||
const int color_depth = driver->GetDisplayMode().ColorDepth;
|
||||
if (color_depth == 0) {
|
||||
filter_error = "Graphics mode is not set";
|
||||
return PGfxFilter();
|
||||
}
|
||||
|
||||
std::shared_ptr<TGfxFilterClass> filter(CreateFilter(id));
|
||||
if (!filter) {
|
||||
filter_error = "Filter does not exist";
|
||||
return PGfxFilter();
|
||||
}
|
||||
|
||||
if (!filter->Initialize(color_depth, filter_error)) {
|
||||
return PGfxFilter();
|
||||
}
|
||||
|
||||
driver->SetGraphicsFilter(filter);
|
||||
return filter;
|
||||
}
|
||||
|
||||
protected:
|
||||
GfxDriverFactoryBase()
|
||||
: _driver(nullptr) {
|
||||
}
|
||||
|
||||
virtual TGfxDriverClass *EnsureDriverCreated() = 0;
|
||||
virtual TGfxFilterClass *CreateFilter(const String &id) = 0;
|
||||
|
||||
TGfxDriverClass *_driver;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
49
engines/ags/engine/gfx/gfx_mode_list.h
Normal file
49
engines/ags/engine/gfx/gfx_mode_list.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Supported graphics mode interface
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX__GFXMODELIST_H
|
||||
#define AGS_ENGINE_GFX__GFXMODELIST_H
|
||||
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/engine/gfx/gfx_defines.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
class IGfxModeList {
|
||||
public:
|
||||
virtual ~IGfxModeList() {}
|
||||
virtual int GetModeCount() const = 0;
|
||||
virtual bool GetMode(int index, DisplayMode &mode) const = 0;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
128
engines/ags/engine/gfx/gfx_util.cpp
Normal file
128
engines/ags/engine/gfx/gfx_util.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/std/memory.h"
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/engine/gfx/gfx_util.h"
|
||||
#include "ags/engine/gfx/blender.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
using namespace Shared;
|
||||
|
||||
namespace GfxUtil {
|
||||
|
||||
Bitmap *ConvertBitmap(Bitmap *src, int dst_color_depth) {
|
||||
int src_col_depth = src->GetColorDepth();
|
||||
if (src_col_depth != dst_color_depth) {
|
||||
int old_conv = get_color_conversion();
|
||||
// TODO: find out what is this, and why do we need to call this every time (do we?)
|
||||
set_color_conversion(COLORCONV_KEEP_TRANS | COLORCONV_TOTAL);
|
||||
Bitmap *dst = BitmapHelper::CreateBitmapCopy(src, dst_color_depth);
|
||||
set_color_conversion(old_conv);
|
||||
return dst;
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
|
||||
struct BlendModeSetter {
|
||||
// Blender setter for destination with and without alpha channel;
|
||||
// assign kRgbToRgbBlender if not supported
|
||||
BlenderMode AllAlpha; // src w alpha -> dst w alpha
|
||||
BlenderMode AlphaToOpaque; // src w alpha -> dst w/o alpha
|
||||
BlenderMode OpaqueToAlpha; // src w/o alpha -> dst w alpha
|
||||
BlenderMode OpaqueToAlphaNoTrans; // src w/o alpha -> dst w alpha (opt-ed for no transparency)
|
||||
BlenderMode AllOpaque; // src w/o alpha -> dst w/o alpha
|
||||
};
|
||||
|
||||
// Array of blender descriptions
|
||||
// NOTE: set kRgbToRgbBlender to fallback to common image blitting
|
||||
static const BlendModeSetter BlendModeSets[kNumBlendModes] = {
|
||||
{ kRgbToRgbBlender, kRgbToRgbBlender, kRgbToRgbBlender, kRgbToRgbBlender, kRgbToRgbBlender }, // kBlendMode_NoAlpha
|
||||
{ kArgbToArgbBlender, kArgbToRgbBlender, kRgbToArgbBlender, kOpaqueBlenderMode, kRgbToRgbBlender }, // kBlendMode_Alpha
|
||||
// NOTE: add new modes here
|
||||
};
|
||||
|
||||
bool SetBlender(BlendMode blend_mode, bool dst_has_alpha, bool src_has_alpha, int blend_alpha) {
|
||||
if (blend_mode < 0 || blend_mode >= kNumBlendModes)
|
||||
return false;
|
||||
const BlendModeSetter &set = BlendModeSets[blend_mode];
|
||||
BlenderMode blender;
|
||||
if (dst_has_alpha)
|
||||
blender = src_has_alpha ? set.AllAlpha :
|
||||
(blend_alpha == 0xFF ? set.OpaqueToAlphaNoTrans : set.OpaqueToAlpha);
|
||||
else
|
||||
blender = src_has_alpha ? set.AlphaToOpaque : set.AllOpaque;
|
||||
|
||||
set_blender_mode(blender, 0, 0, 0, blend_alpha);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrawSpriteBlend(Bitmap *ds, const Point &ds_at, Bitmap *sprite,
|
||||
BlendMode blend_mode, bool dst_has_alpha, bool src_has_alpha, int blend_alpha) {
|
||||
if (blend_alpha <= 0)
|
||||
return; // do not draw 100% transparent image
|
||||
|
||||
if (// support only 32-bit blending at the moment
|
||||
ds->GetColorDepth() == 32 && sprite->GetColorDepth() == 32 &&
|
||||
// set blenders if applicable and tell if succeeded
|
||||
SetBlender(blend_mode, dst_has_alpha, src_has_alpha, blend_alpha)) {
|
||||
ds->TransBlendBlt(sprite, ds_at.X, ds_at.Y);
|
||||
} else {
|
||||
GfxUtil::DrawSpriteWithTransparency(ds, sprite, ds_at.X, ds_at.Y, blend_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSpriteWithTransparency(Bitmap *ds, Bitmap *sprite, int x, int y, int alpha) {
|
||||
if (alpha <= 0) {
|
||||
// fully transparent, don't draw it at all
|
||||
return;
|
||||
}
|
||||
|
||||
const int surface_depth = ds->GetColorDepth();
|
||||
const int sprite_depth = sprite->GetColorDepth();
|
||||
|
||||
// Allegro does not support masked blit or blend between different formats
|
||||
// *except* when drawing 8-bit sprites onto a higher dest.
|
||||
std::unique_ptr<Bitmap> conv_bm;
|
||||
if ((surface_depth != sprite_depth) && (sprite_depth > 8)) {
|
||||
// use ConvertBitmap in order to keep mask pixels
|
||||
conv_bm.reset(ConvertBitmap(sprite, surface_depth));
|
||||
sprite = conv_bm.get();
|
||||
}
|
||||
|
||||
if ((alpha < 0xFF) && (surface_depth > 8) && (sprite_depth > 8)) {
|
||||
set_trans_blender(0, 0, 0, alpha);
|
||||
ds->TransBlendBlt(sprite, x, y);
|
||||
} else {
|
||||
ds->Blit(sprite, x, y, kBitmap_Transparency);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GfxUtil
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
69
engines/ags/engine/gfx/gfx_util.h
Normal file
69
engines/ags/engine/gfx/gfx_util.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Intermediate level drawing utility functions.
|
||||
//
|
||||
// GfxUtil namespace is meant for intermediate-to-lower level functions, that
|
||||
// implement specific conversions, tricks and hacks for drawing bitmaps and
|
||||
// geometry.
|
||||
// The suggested convention is to add only those functions, that do not require
|
||||
// any knowledge of higher-level engine types and objects.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_GFX_UTIL_H
|
||||
#define AGS_ENGINE_GFX_GFX_UTIL_H
|
||||
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/shared/gfx/gfx_def.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
using Shared::Bitmap;
|
||||
|
||||
namespace GfxUtil {
|
||||
// Creates a COPY of the source bitmap, converted to the given format.
|
||||
// Keeps mask pixels intact, only converting mask color value if necessary.
|
||||
Bitmap *ConvertBitmap(Bitmap *src, int dst_color_depth);
|
||||
|
||||
// Considers the given information about source and destination surfaces,
|
||||
// then draws a bimtap over another either using requested blending mode,
|
||||
// or fallbacks to common "magic pink" transparency mode;
|
||||
// optionally uses blending alpha (overall image transparency).
|
||||
void DrawSpriteBlend(Bitmap *ds, const Point &ds_at, Bitmap *sprite,
|
||||
Shared::BlendMode blend_mode, bool dst_has_alpha = true, bool src_has_alpha = true, int blend_alpha = 0xFF);
|
||||
|
||||
// Draws a bitmap over another one with given alpha level (0 - 255),
|
||||
// takes account of the bitmap's mask color,
|
||||
// ignores image's alpha channel, even if there's one;
|
||||
// does a conversion if sprite and destination color depths do not match.
|
||||
void DrawSpriteWithTransparency(Bitmap *ds, Bitmap *sprite, int x, int y, int alpha = 0xFF);
|
||||
} // namespace GfxUtil
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
78
engines/ags/engine/gfx/gfxfilter.h
Normal file
78
engines/ags/engine/gfx/gfxfilter.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Graphics filter interface
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_GFXFILTER_H
|
||||
#define AGS_ENGINE_GFX_GFXFILTER_H
|
||||
|
||||
#include "common/std/memory.h"
|
||||
#include "ags/shared/util/geometry.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
using Shared::String;
|
||||
|
||||
struct GfxFilterInfo {
|
||||
String Id;
|
||||
String Name;
|
||||
int MinScale;
|
||||
int MaxScale;
|
||||
|
||||
GfxFilterInfo() {
|
||||
}
|
||||
GfxFilterInfo(String id, String name, int min_scale = 0, int max_scale = 0)
|
||||
: Id(id)
|
||||
, Name(name)
|
||||
, MinScale(min_scale)
|
||||
, MaxScale(max_scale) {
|
||||
}
|
||||
};
|
||||
|
||||
class IGfxFilter {
|
||||
public:
|
||||
virtual ~IGfxFilter() {}
|
||||
|
||||
virtual const GfxFilterInfo &GetInfo() const = 0;
|
||||
|
||||
// Init filter for the specified color depth
|
||||
virtual bool Initialize(const int color_depth, String &err_str) = 0;
|
||||
virtual void UnInitialize() = 0;
|
||||
// Try to set rendering translation; returns actual supported destination rect
|
||||
virtual Rect SetTranslation(const Size src_size, const Rect dst_rect) = 0;
|
||||
// Get defined destination rect for this filter
|
||||
virtual Rect GetDestination() const = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IGfxFilter> PGfxFilter;
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
50
engines/ags/engine/gfx/gfxfilter_scaling.cpp
Normal file
50
engines/ags/engine/gfx/gfxfilter_scaling.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/engine/gfx/gfxfilter_scaling.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
bool ScalingGfxFilter::Initialize(const int /*color_depth*/, String & /*err_str*/) {
|
||||
// succeed by default
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScalingGfxFilter::UnInitialize() {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
Rect ScalingGfxFilter::SetTranslation(const Size src_size, const Rect dst_rect) {
|
||||
// do not restrict scaling by default
|
||||
_dstRect = dst_rect;
|
||||
_scaling.Init(src_size, dst_rect);
|
||||
return _dstRect;
|
||||
}
|
||||
|
||||
Rect ScalingGfxFilter::GetDestination() const {
|
||||
return _dstRect;
|
||||
}
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
56
engines/ags/engine/gfx/gfxfilter_scaling.h
Normal file
56
engines/ags/engine/gfx/gfxfilter_scaling.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Base class for graphic filter which provides virtual screen scaling
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_SCALING_GFX_FILTER_H
|
||||
#define AGS_ENGINE_GFX_SCALING_GFX_FILTER_H
|
||||
|
||||
#include "ags/engine/gfx/gfxfilter.h"
|
||||
#include "ags/shared/util/scaling.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
|
||||
using AGS::Shared::PlaneScaling;
|
||||
|
||||
class ScalingGfxFilter : public IGfxFilter {
|
||||
public:
|
||||
bool Initialize(const int color_depth, String &err_str) override;
|
||||
void UnInitialize() override;
|
||||
Rect SetTranslation(const Size src_size, const Rect dst_rect) override;
|
||||
Rect GetDestination() const override;
|
||||
|
||||
protected:
|
||||
Rect _dstRect;
|
||||
PlaneScaling _scaling;
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
37
engines/ags/engine/gfx/gfxfilter_scummvm_renderer.cpp
Normal file
37
engines/ags/engine/gfx/gfxfilter_scummvm_renderer.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/engine/gfx/gfxfilter_scummvm_renderer.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
namespace ALSW {
|
||||
|
||||
const GfxFilterInfo &ScummVMRendererGfxFilter::GetInfo() const {
|
||||
return _GP(scummvmGfxFilter);
|
||||
}
|
||||
|
||||
} // namespace ALSW
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
51
engines/ags/engine/gfx/gfxfilter_scummvm_renderer.h
Normal file
51
engines/ags/engine/gfx/gfxfilter_scummvm_renderer.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// SDL software renderer filter. Technically a non-op, as SDL_Renderer
|
||||
// does the job.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_SCUMMVM_RENDERER_FILTER_H
|
||||
#define AGS_ENGINE_GFX_SCUMMVM_RENDERER_FILTER_H
|
||||
|
||||
#include "ags/engine/gfx/gfxfilter_scaling.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
namespace ALSW {
|
||||
|
||||
class ScummVMRendererGfxFilter : public ScalingGfxFilter {
|
||||
public:
|
||||
~ScummVMRendererGfxFilter() override {}
|
||||
|
||||
const GfxFilterInfo &GetInfo() const override;
|
||||
};
|
||||
|
||||
} // namespace ALSW
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
265
engines/ags/engine/gfx/graphics_driver.h
Normal file
265
engines/ags/engine/gfx/graphics_driver.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Graphics driver interface
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_ENGINE_GFX_GRAPHICS_DRIVER_H
|
||||
#define AGS_ENGINE_GFX_GRAPHICS_DRIVER_H
|
||||
|
||||
//#include "math/matrix.h"
|
||||
#include "common/std/memory.h"
|
||||
#include "ags/lib/allegro.h" // RGB, PALETTE
|
||||
#include "ags/shared/gfx/gfx_def.h"
|
||||
#include "ags/engine/gfx/gfx_defines.h"
|
||||
#include "ags/engine/gfx/gfx_mode_list.h"
|
||||
#include "ags/shared/util/geometry.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
|
||||
namespace Shared {
|
||||
class Bitmap;
|
||||
typedef std::shared_ptr<Shared::Bitmap> PBitmap;
|
||||
} // namespace Shared
|
||||
|
||||
namespace Engine {
|
||||
|
||||
// Forward declaration
|
||||
class IDriverDependantBitmap;
|
||||
class IGfxFilter;
|
||||
typedef std::shared_ptr<IGfxFilter> PGfxFilter;
|
||||
using Shared::PBitmap;
|
||||
|
||||
enum TintMethod {
|
||||
TintReColourise = 0,
|
||||
TintSpecifyMaximum = 1
|
||||
};
|
||||
|
||||
struct SpriteColorTransform {
|
||||
int Alpha = 255; // alpha color value (0 - 255)
|
||||
|
||||
SpriteColorTransform() = default;
|
||||
SpriteColorTransform(int alpha) : Alpha(alpha) {
|
||||
}
|
||||
};
|
||||
|
||||
// Sprite transformation
|
||||
// TODO: combine with stretch parameters in the IDriverDependantBitmap?
|
||||
struct SpriteTransform {
|
||||
// Translate
|
||||
int X = 0, Y = 0;
|
||||
float ScaleX = 1.f, ScaleY = 1.f;
|
||||
float Rotate = 0.f; // angle, in radians
|
||||
SpriteColorTransform Color;
|
||||
|
||||
SpriteTransform() = default;
|
||||
SpriteTransform(int x, int y, float scalex = 1.0f, float scaley = 1.0f, float rotate = 0.0f,
|
||||
SpriteColorTransform color = SpriteColorTransform())
|
||||
: X(x), Y(y), ScaleX(scalex), ScaleY(scaley), Rotate(rotate), Color(color) {
|
||||
}
|
||||
};
|
||||
|
||||
// Describes 3 render matrixes: world, view and projection
|
||||
struct RenderMatrixes {
|
||||
/*
|
||||
glm::mat4 World;
|
||||
glm::mat4 View;
|
||||
glm::mat4 Projection;
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
typedef void (*GFXDRV_CLIENTCALLBACK)();
|
||||
typedef bool (*GFXDRV_CLIENTCALLBACKEVT)(int evt, int data);
|
||||
typedef void (*GFXDRV_CLIENTCALLBACKINITGFX)(void *data);
|
||||
|
||||
class IGraphicsDriver {
|
||||
public:
|
||||
// Gets graphic driver's identifier
|
||||
virtual const char *GetDriverID() = 0;
|
||||
// Gets graphic driver's "friendly name"
|
||||
virtual const char *GetDriverName() = 0;
|
||||
|
||||
// Tells if this gfx driver has to redraw whole scene each time
|
||||
virtual bool RequiresFullRedrawEachFrame() = 0;
|
||||
// Tells if this gfx driver uses GPU to transform sprites
|
||||
virtual bool HasAcceleratedTransform() = 0;
|
||||
// Tells if this gfx driver draws on a virtual screen before rendering on real screen.
|
||||
virtual bool UsesMemoryBackBuffer() = 0;
|
||||
// Tells if this gfx driver requires releasing render targets
|
||||
// in case of display mode change or reset.
|
||||
virtual bool ShouldReleaseRenderTargets() = 0;
|
||||
|
||||
virtual void SetTintMethod(TintMethod method) = 0;
|
||||
// Initialize given display mode
|
||||
virtual bool SetDisplayMode(const DisplayMode &mode) = 0;
|
||||
// Updates previously set display mode, accommodating to the new screen size
|
||||
virtual void UpdateDeviceScreen(const Size &screen_size) = 0;
|
||||
// Gets if a graphics mode was initialized
|
||||
virtual bool IsModeSet() const = 0;
|
||||
// Set the size of the native image size
|
||||
virtual bool SetNativeResolution(const GraphicResolution &native_res) = 0;
|
||||
virtual bool IsNativeSizeValid() const = 0;
|
||||
// Set game render frame and translation
|
||||
virtual bool SetRenderFrame(const Rect &dst_rect) = 0;
|
||||
virtual bool IsRenderFrameValid() const = 0;
|
||||
// Report which color depth options are best suited for the given native color depth
|
||||
virtual int GetDisplayDepthForNativeDepth(int native_color_depth) const = 0;
|
||||
virtual IGfxModeList *GetSupportedModeList(int color_depth) = 0;
|
||||
virtual bool IsModeSupported(const DisplayMode &mode) = 0;
|
||||
virtual DisplayMode GetDisplayMode() const = 0;
|
||||
virtual PGfxFilter GetGraphicsFilter() const = 0;
|
||||
virtual Size GetNativeSize() const = 0;
|
||||
virtual Rect GetRenderDestination() const = 0;
|
||||
virtual void SetCallbackForPolling(GFXDRV_CLIENTCALLBACK callback) = 0;
|
||||
// TODO: get rid of draw screen callback at some point when all fade functions are more or less grouped in one
|
||||
virtual void SetCallbackToDrawScreen(GFXDRV_CLIENTCALLBACK callback, GFXDRV_CLIENTCALLBACK post_callback) = 0;
|
||||
virtual void SetCallbackOnInit(GFXDRV_CLIENTCALLBACKINITGFX callback) = 0;
|
||||
// The event callback is called in the main render loop when a
|
||||
// event entry is encountered inside a sprite list.
|
||||
// You can use this to hook into the rendering process.
|
||||
virtual void SetCallbackOnSpriteEvt(GFXDRV_CLIENTCALLBACKEVT callback) = 0;
|
||||
// Clears the screen rectangle. The coordinates are expected in the **native game resolution**.
|
||||
virtual void ClearRectangle(int x1, int y1, int x2, int y2, RGB *colorToUse) = 0;
|
||||
// Gets closest recommended bitmap format (currently - only color depth) for the given original format.
|
||||
// Engine needs to have game bitmaps brought to the certain range of formats, easing conversion into the video bitmaps.
|
||||
virtual int GetCompatibleBitmapFormat(int color_depth) = 0;
|
||||
// Returns available texture memory, or 0 if this query is not supported
|
||||
virtual size_t GetAvailableTextureMemory() = 0;
|
||||
|
||||
// Creates a "raw" DDB, without pixel initialization
|
||||
virtual IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque = false) = 0;
|
||||
// Creates DDB, initializes from the given bitmap.
|
||||
virtual IDriverDependantBitmap *CreateDDBFromBitmap(Shared::Bitmap *bitmap, bool has_alpha, bool opaque = false) = 0;
|
||||
// Creates DDB intended to be used as a render target (allow render other DDBs on it).
|
||||
virtual IDriverDependantBitmap *CreateRenderTargetDDB(int width, int height, int color_depth, bool opaque = false) = 0;
|
||||
// Updates DBB using the given bitmap; bitmap must have same size and format
|
||||
// as the one that this DDB was initialized with.
|
||||
virtual void UpdateDDBFromBitmap(IDriverDependantBitmap *bitmapToUpdate, Shared::Bitmap *bitmap, bool has_alpha) = 0;
|
||||
// Destroy the DDB.
|
||||
virtual void DestroyDDB(IDriverDependantBitmap *bitmap) = 0;
|
||||
|
||||
// Get shared texture from cache, or create from bitmap and assign ID
|
||||
// FIXME: opaque should be either texture data's flag, - in which case same sprite_id
|
||||
// will be either opaque or not opaque, - or DDB's flag, but in that case it cannot
|
||||
// be applied to the shared texture data. Currently it's possible to share same
|
||||
// texture data, but update it with different "opaque" values, which breaks logic.
|
||||
virtual IDriverDependantBitmap *GetSharedDDB(uint32_t sprite_id,
|
||||
Shared::Bitmap *bitmap = nullptr, bool has_alpha = true, bool opaque = false) = 0;
|
||||
virtual void UpdateSharedDDB(uint32_t sprite_id, Shared::Bitmap *bitmap = nullptr, bool has_alpha = true, bool opaque = false) = 0;
|
||||
// Removes the shared texture reference, will force the texture to recreate next time
|
||||
virtual void ClearSharedDDB(uint32_t sprite_id) = 0;
|
||||
|
||||
// Prepares next sprite batch, a list of sprites with defined viewport and optional
|
||||
// global model transformation; all subsequent calls to DrawSprite will be adding
|
||||
// sprites to this batch's list.
|
||||
// Beginning a batch while the previous was not ended will create a sub-batch
|
||||
// (think of it as of a child scene node).
|
||||
// Optionally you can assign "filter flags" to this batch; this lets to filter certain
|
||||
// batches out during some operations, such as fading effects or making screenshots.
|
||||
virtual void BeginSpriteBatch(const Rect &viewport, const SpriteTransform &transform = SpriteTransform(),
|
||||
Shared::GraphicFlip flip = Shared::kFlip_None, PBitmap surface = nullptr, uint32_t filter_flags = 0) = 0;
|
||||
// Ends current sprite batch
|
||||
virtual void EndSpriteBatch() = 0;
|
||||
// Adds sprite to the active batch
|
||||
virtual void DrawSprite(int x, int y, IDriverDependantBitmap *bitmap) = 0;
|
||||
// Adds fade overlay fx to the active batch
|
||||
virtual void SetScreenFade(int red, int green, int blue) = 0;
|
||||
// Adds tint overlay fx to the active batch
|
||||
// TODO: redesign this to allow various post-fx per sprite batch?
|
||||
virtual void SetScreenTint(int red, int green, int blue) = 0;
|
||||
// Sets stage screen parameters for the current batch.
|
||||
// Currently includes size and optional position offset;
|
||||
// the position is relative, as stage screens are using sprite batch transforms.
|
||||
// Stage screens are used to let plugins do raw drawing during render callbacks.
|
||||
// TODO: find a better term? note, it's used in several places around renderers.
|
||||
virtual void SetStageScreen(const Size &sz, int x = 0, int y = 0) = 0;
|
||||
// Clears all sprite batches, resets batch counter
|
||||
virtual void ClearDrawLists() = 0;
|
||||
virtual void RenderToBackBuffer() = 0;
|
||||
virtual void Render() = 0;
|
||||
// Renders with additional final offset and flip
|
||||
// TODO: leftover from old code, solely for software renderer; remove when
|
||||
// software mode either discarded or scene node graph properly implemented.
|
||||
virtual void Render(int xoff, int yoff, Shared::GraphicFlip flip) = 0;
|
||||
// Copies contents of the game screen into bitmap using simple blit or pixel copy.
|
||||
// Bitmap must be of supported size and pixel format. If it's not the method will
|
||||
// fail and optionally write wanted destination format into 'want_fmt' pointer.
|
||||
virtual bool GetCopyOfScreenIntoBitmap(Shared::Bitmap *destination, const Rect *src_rect, bool at_native_res,
|
||||
GraphicResolution *want_fmt = nullptr, uint32_t batch_skip_filter = 0u) = 0;
|
||||
// Tells if the renderer supports toggling vsync after initializing the mode.
|
||||
virtual bool DoesSupportVsyncToggle() = 0;
|
||||
// Toggles vertical sync mode, if renderer supports one; returns the *new state*.
|
||||
virtual bool SetVsync(bool enabled) = 0;
|
||||
// Tells if the renderer currently has vsync enabled.
|
||||
virtual bool GetVsync() const = 0;
|
||||
// Enables or disables rendering mode that draws sprite list directly into
|
||||
// the final resolution, as opposed to drawing to native-resolution buffer
|
||||
// and scaling to final frame. The effect may be that sprites that are
|
||||
// drawn with additional fractional scaling will appear more detailed than
|
||||
// the rest of the game. The effect is stronger for the low-res games being
|
||||
// rendered in the high-res mode.
|
||||
virtual void RenderSpritesAtScreenResolution(bool enabled) = 0;
|
||||
// TODO: move fade-in/out/boxout functions out of the graphics driver!! make everything render through
|
||||
// main drawing procedure. Since currently it does not - we need to init our own sprite batch
|
||||
// internally to let it set up correct viewport settings instead of relying on a chance.
|
||||
// Runs fade-out animation in a blocking manner.
|
||||
virtual void FadeOut(int speed, int targetColourRed, int targetColourGreen, int targetColourBlue,
|
||||
uint32_t batch_skip_filter = 0u) = 0;
|
||||
// Runs fade-in animation in a blocking manner.
|
||||
virtual void FadeIn(int speed, PALETTE p, int targetColourRed, int targetColourGreen, int targetColourBlue,
|
||||
uint32_t batch_skip_filter = 0u) = 0;
|
||||
// Runs box-out animation in a blocking manner.
|
||||
virtual void BoxOutEffect(bool blackingOut, int speed, int delay, uint32_t batch_skip_filter = 0u) = 0;
|
||||
virtual void UseSmoothScaling(bool enabled) = 0;
|
||||
virtual bool SupportsGammaControl() = 0;
|
||||
virtual void SetGamma(int newGamma) = 0;
|
||||
// Returns the virtual screen. Will return NULL if renderer does not support memory backbuffer.
|
||||
// In normal case you should use GetStageBackBuffer() instead.
|
||||
virtual Shared::Bitmap *GetMemoryBackBuffer() = 0;
|
||||
// Sets custom backbuffer bitmap to render to.
|
||||
// Passing NULL pointer will tell renderer to switch back to its original virtual screen.
|
||||
// Note that only software renderer supports this.
|
||||
virtual void SetMemoryBackBuffer(Shared::Bitmap *backBuffer) = 0;
|
||||
// Returns memory backbuffer for the current rendering stage (or base virtual screen if called outside of render pass).
|
||||
// All renderers should support this.
|
||||
virtual Shared::Bitmap *GetStageBackBuffer(bool mark_dirty = false) = 0;
|
||||
// Sets custom backbuffer bitmap to render current render stage to.
|
||||
// Passing NULL pointer will tell renderer to switch back to its original stage buffer.
|
||||
// Note that only software renderer supports this.
|
||||
virtual void SetStageBackBuffer(Shared::Bitmap *backBuffer) = 0;
|
||||
// Retrieves 3 transform matrixes for the current rendering stage: world (model), view and projection.
|
||||
// These matrixes will be filled in accordance to the renderer's compatible format;
|
||||
// returns false if renderer does not use matrixes (not a 3D renderer).
|
||||
virtual bool GetStageMatrixes(RenderMatrixes &rm) = 0;
|
||||
|
||||
virtual ~IGraphicsDriver() {}
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user