Initial commit
This commit is contained in:
316
backends/graphics/android/android-graphics.cpp
Normal file
316
backends/graphics/android/android-graphics.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Allow use of stuff in <time.h>
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
|
||||
// Disable printf override in common/forbidden.h to avoid
|
||||
// clashes with log.h from the Android SDK.
|
||||
// That header file uses
|
||||
// __attribute__ ((format(printf, 3, 4)))
|
||||
// which gets messed up by our override mechanism; this could
|
||||
// be avoided by either changing the Android SDK to use the equally
|
||||
// legal and valid
|
||||
// __attribute__ ((format(printf, 3, 4)))
|
||||
// or by refining our printf override to use a varadic macro
|
||||
// (which then wouldn't be portable, though).
|
||||
// Anyway, for now we just disable the printf override globally
|
||||
// for the Android port
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
|
||||
|
||||
#include "backends/platform/android/android.h"
|
||||
#include "backends/platform/android/jni-android.h"
|
||||
#include "backends/graphics/android/android-graphics.h"
|
||||
#include "backends/graphics/opengl/pipelines/pipeline.h"
|
||||
#include "backends/graphics/opengl/texture.h"
|
||||
|
||||
#include "graphics/blit.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
//
|
||||
// AndroidGraphicsManager
|
||||
//
|
||||
AndroidGraphicsManager::AndroidGraphicsManager() :
|
||||
_touchcontrols(nullptr),
|
||||
_old_touch_mode(OSystem_Android::TOUCH_MODE_TOUCHPAD) {
|
||||
ENTER();
|
||||
|
||||
// Initialize our OpenGL ES context.
|
||||
initSurface();
|
||||
|
||||
_rendering3d = (_renderer3d != nullptr);
|
||||
// maybe in 3D, not in GUI
|
||||
dynamic_cast<OSystem_Android *>(g_system)->applyTouchSettings(_rendering3d, false);
|
||||
dynamic_cast<OSystem_Android *>(g_system)->applyOrientationSettings();
|
||||
}
|
||||
|
||||
AndroidGraphicsManager::~AndroidGraphicsManager() {
|
||||
ENTER();
|
||||
|
||||
deinitSurface();
|
||||
|
||||
delete _touchcontrols;
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::initSurface() {
|
||||
LOGD("initializing 2D surface");
|
||||
|
||||
assert(!JNI::haveSurface());
|
||||
if (!JNI::initSurface()) {
|
||||
error("JNI::initSurface failed");
|
||||
}
|
||||
|
||||
if (JNI::egl_bits_per_pixel == 16) {
|
||||
// We default to RGB565 and RGBA5551 which is closest to what we setup in Java side
|
||||
notifyContextCreate(OpenGL::kContextGLES2,
|
||||
new OpenGL::Backbuffer(),
|
||||
Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0),
|
||||
Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
|
||||
} else {
|
||||
// If not 16, this must be 24 or 32 bpp so make use of them
|
||||
notifyContextCreate(OpenGL::kContextGLES2,
|
||||
new OpenGL::Backbuffer(),
|
||||
OpenGL::Texture::getRGBPixelFormat(),
|
||||
OpenGL::Texture::getRGBAPixelFormat()
|
||||
);
|
||||
}
|
||||
|
||||
if (_touchcontrols) {
|
||||
_touchcontrols->recreate();
|
||||
_touchcontrols->updateGLTexture();
|
||||
} else {
|
||||
_touchcontrols = createSurface(_defaultFormatAlpha);
|
||||
}
|
||||
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
|
||||
this, JNI::egl_surface_width, JNI::egl_surface_height);
|
||||
|
||||
handleResize(JNI::egl_surface_width, JNI::egl_surface_height);
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::deinitSurface() {
|
||||
if (!JNI::haveSurface())
|
||||
return;
|
||||
|
||||
LOGD("deinitializing 2D surface");
|
||||
|
||||
// Deregister us from touch control
|
||||
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
|
||||
nullptr, 0, 0);
|
||||
if (_touchcontrols) {
|
||||
_touchcontrols->destroy();
|
||||
}
|
||||
|
||||
notifyContextDestroy();
|
||||
|
||||
JNI::deinitSurface();
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::resizeSurface() {
|
||||
|
||||
// If we had lost surface just init it again
|
||||
if (!JNI::haveSurface()) {
|
||||
initSurface();
|
||||
return;
|
||||
}
|
||||
|
||||
// Recreate the EGL surface, context is preserved
|
||||
JNI::deinitSurface();
|
||||
if (!JNI::initSurface()) {
|
||||
error("JNI::initSurface failed");
|
||||
}
|
||||
|
||||
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().setDrawer(
|
||||
this, JNI::egl_surface_width, JNI::egl_surface_height);
|
||||
|
||||
handleResize(JNI::egl_surface_width, JNI::egl_surface_height);
|
||||
}
|
||||
|
||||
|
||||
void AndroidGraphicsManager::updateScreen() {
|
||||
//ENTER();
|
||||
|
||||
if (!JNI::haveSurface())
|
||||
return;
|
||||
|
||||
// Sets _forceRedraw if needed
|
||||
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().beforeDraw();
|
||||
|
||||
OpenGLGraphicsManager::updateScreen();
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::displayMessageOnOSD(const Common::U32String &msg) {
|
||||
ENTER("%s", msg.encode().c_str());
|
||||
|
||||
JNI::displayMessageOnOSD(msg);
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::recalculateDisplayAreas() {
|
||||
Common::Rect oldDrawRect = _activeArea.drawRect;
|
||||
|
||||
OpenGLGraphicsManager::recalculateDisplayAreas();
|
||||
|
||||
int offsetX = _activeArea.drawRect.left - oldDrawRect.left;
|
||||
int offsetY = _activeArea.drawRect.top - oldDrawRect.top;
|
||||
|
||||
int newX = _cursorX + offsetX;
|
||||
int newY = _cursorY + offsetY;
|
||||
|
||||
newX = CLIP<int16>(newX, _activeArea.drawRect.left, _activeArea.drawRect.right);
|
||||
newY = CLIP<int16>(newY, _activeArea.drawRect.top, _activeArea.drawRect.bottom);
|
||||
|
||||
setMousePosition(newX, newY);
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::showOverlay(bool inGUI) {
|
||||
if (_overlayVisible && inGUI == _overlayInGUI)
|
||||
return;
|
||||
|
||||
// Don't change touch mode when not changing mouse coordinates
|
||||
if (inGUI) {
|
||||
_old_touch_mode = JNI::getTouchMode();
|
||||
// maybe in 3D, in overlay
|
||||
dynamic_cast<OSystem_Android *>(g_system)->applyTouchSettings(_renderer3d != nullptr, true);
|
||||
dynamic_cast<OSystem_Android *>(g_system)->applyOrientationSettings();
|
||||
} else if (_overlayInGUI) {
|
||||
// Restore touch mode active before overlay was shown
|
||||
JNI::setTouchMode(_old_touch_mode);
|
||||
}
|
||||
|
||||
OpenGL::OpenGLGraphicsManager::showOverlay(inGUI);
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::hideOverlay() {
|
||||
if (!_overlayVisible)
|
||||
return;
|
||||
|
||||
if (_overlayInGUI) {
|
||||
// Restore touch mode active before overlay was shown
|
||||
JNI::setTouchMode(_old_touch_mode);
|
||||
dynamic_cast<OSystem_Android *>(g_system)->applyOrientationSettings();
|
||||
}
|
||||
|
||||
OpenGL::OpenGLGraphicsManager::hideOverlay();
|
||||
}
|
||||
|
||||
float AndroidGraphicsManager::getHiDPIScreenFactor() const {
|
||||
JNI::DPIValues dpi;
|
||||
JNI::getDPI(dpi);
|
||||
// Scale down the Android factor else the GUI is too big and
|
||||
// there is not much options to go smaller
|
||||
return dpi[2] / 1.2f;
|
||||
}
|
||||
|
||||
bool AndroidGraphicsManager::loadVideoMode(uint requestedWidth, uint requestedHeight, bool resizable, int antialiasing) {
|
||||
ENTER("%d, %d, %s", requestedWidth, requestedHeight, format.toString().c_str());
|
||||
|
||||
// As GLES2 provides FBO, OpenGL graphics manager must ask us for a resizable surface
|
||||
assert(resizable);
|
||||
if (antialiasing != 0) {
|
||||
warning("Requesting antialiased video mode while not available");
|
||||
}
|
||||
|
||||
const bool render3d = (_renderer3d != nullptr);
|
||||
if (_rendering3d != render3d) {
|
||||
_rendering3d = render3d;
|
||||
// 3D status changed: refresh the touch mode
|
||||
applyTouchSettings();
|
||||
}
|
||||
|
||||
// We get this whenever a new resolution is requested. Since Android is
|
||||
// using a fixed output size we do nothing like that here.
|
||||
return true;
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::refreshScreen() {
|
||||
//ENTER();
|
||||
|
||||
// Last minute draw of touch controls
|
||||
dynamic_cast<OSystem_Android *>(g_system)->getTouchControls().draw();
|
||||
|
||||
JNI::swapBuffers();
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::applyTouchSettings() const {
|
||||
// maybe in 3D, maybe in GUI
|
||||
dynamic_cast<OSystem_Android *>(g_system)->applyTouchSettings(_renderer3d != nullptr, _overlayVisible && _overlayInGUI);
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::syncVirtkeyboardState(bool virtkeybd_on) {
|
||||
_screenAlign = SCREEN_ALIGN_CENTER;
|
||||
if (virtkeybd_on) {
|
||||
_screenAlign |= SCREEN_ALIGN_TOP;
|
||||
} else {
|
||||
_screenAlign |= SCREEN_ALIGN_MIDDLE;
|
||||
}
|
||||
recalculateDisplayAreas();
|
||||
_forceRedraw = true;
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::touchControlInitSurface(const Graphics::ManagedSurface &surf) {
|
||||
if (_touchcontrols->getWidth() == surf.w && _touchcontrols->getHeight() == surf.h) {
|
||||
return;
|
||||
}
|
||||
|
||||
_touchcontrols->allocate(surf.w, surf.h);
|
||||
Graphics::Surface *dst = _touchcontrols->getSurface();
|
||||
|
||||
Graphics::crossBlit(
|
||||
(byte *)dst->getPixels(), (const byte *)surf.getPixels(),
|
||||
dst->pitch, surf.pitch,
|
||||
surf.w, surf.h,
|
||||
dst->format, surf.format);
|
||||
_touchcontrols->updateGLTexture();
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::touchControlDraw(uint8 alpha, int16 x, int16 y, int16 w, int16 h, const Common::Rect &clip) {
|
||||
_targetBuffer->enableBlend(OpenGL::Framebuffer::kBlendModeTraditionalTransparency);
|
||||
OpenGL::Pipeline *pipeline = getPipeline();
|
||||
pipeline->activate();
|
||||
if (alpha != 255) {
|
||||
pipeline->setColor(1.0f, 1.0f, 1.0f, alpha / 255.0f);
|
||||
}
|
||||
pipeline->drawTexture(_touchcontrols->getGLTexture(),
|
||||
x, y, w, h, clip);
|
||||
if (alpha != 255) {
|
||||
pipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidGraphicsManager::touchControlNotifyChanged() {
|
||||
// Make sure we redraw the screen
|
||||
_forceRedraw = true;
|
||||
}
|
||||
|
||||
bool AndroidGraphicsManager::notifyMousePosition(Common::Point &mouse) {
|
||||
mouse.x = CLIP<int16>(mouse.x, _activeArea.drawRect.left, _activeArea.drawRect.right);
|
||||
mouse.y = CLIP<int16>(mouse.y, _activeArea.drawRect.top, _activeArea.drawRect.bottom);
|
||||
|
||||
setMousePosition(mouse.x, mouse.y);
|
||||
mouse = convertWindowToVirtual(mouse.x, mouse.y);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WindowedGraphicsManager::Insets AndroidGraphicsManager::getSafeAreaInsets() const {
|
||||
return WindowedGraphicsManager::Insets{
|
||||
(int16)JNI::cutout_insets[0], (int16)JNI::cutout_insets[1],
|
||||
(int16)JNI::cutout_insets[2], (int16)JNI::cutout_insets[3]};
|
||||
}
|
||||
76
backends/graphics/android/android-graphics.h
Normal file
76
backends/graphics/android/android-graphics.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ANDROID_ANDROID_GRAPHICS_H
|
||||
#define BACKENDS_GRAPHICS_ANDROID_ANDROID_GRAPHICS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "backends/graphics/opengl/opengl-graphics.h"
|
||||
|
||||
#include "backends/platform/android/touchcontrols.h"
|
||||
|
||||
class AndroidGraphicsManager :
|
||||
public OpenGL::OpenGLGraphicsManager, public TouchControlsDrawer {
|
||||
public:
|
||||
AndroidGraphicsManager();
|
||||
virtual ~AndroidGraphicsManager();
|
||||
|
||||
void initSurface();
|
||||
void deinitSurface();
|
||||
void resizeSurface();
|
||||
|
||||
WindowedGraphicsManager::Insets getSafeAreaInsets() const override;
|
||||
|
||||
void updateScreen() override;
|
||||
|
||||
void displayMessageOnOSD(const Common::U32String &msg) override;
|
||||
|
||||
bool notifyMousePosition(Common::Point &mouse);
|
||||
Common::Point getMousePosition() { return Common::Point(_cursorX, _cursorY); }
|
||||
|
||||
float getHiDPIScreenFactor() const override;
|
||||
|
||||
void touchControlInitSurface(const Graphics::ManagedSurface &surf) override;
|
||||
void touchControlNotifyChanged() override;
|
||||
void touchControlDraw(uint8 alpha, int16 x, int16 y, int16 w, int16 h, const Common::Rect &clip) override;
|
||||
|
||||
void syncVirtkeyboardState(bool virtkeybd_on);
|
||||
void applyTouchSettings() const;
|
||||
|
||||
protected:
|
||||
void recalculateDisplayAreas() override;
|
||||
void setSystemMousePosition(const int x, const int y) override {}
|
||||
|
||||
void showOverlay(bool inGUI) override;
|
||||
void hideOverlay() override;
|
||||
|
||||
|
||||
bool loadVideoMode(uint requestedWidth, uint requestedHeight, bool resizable, int antialiasing) override;
|
||||
|
||||
void refreshScreen() override;
|
||||
|
||||
private:
|
||||
OpenGL::Surface *_touchcontrols;
|
||||
int _old_touch_mode;
|
||||
bool _rendering3d;
|
||||
};
|
||||
|
||||
#endif
|
||||
959
backends/graphics/atari/atari-c2p-asm.S
Normal file
959
backends/graphics/atari/atari-c2p-asm.S
Normal file
@@ -0,0 +1,959 @@
|
||||
/* 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 "../../platform/atari/symbols.h"
|
||||
|
||||
| C2P by Mikael Kalms (public domain)
|
||||
| See https://github.com/Kalmalyzer/kalms-c2p
|
||||
|
||||
.globl SYM(asm_c2p1x1_8)
|
||||
.globl SYM(asm_c2p1x1_8_tt)
|
||||
.globl SYM(asm_c2p1x1_8_rect)
|
||||
.globl SYM(asm_c2p1x1_4)
|
||||
.globl SYM(asm_c2p1x1_4_rect)
|
||||
|
||||
|
||||
.text
|
||||
|
||||
| void asm_c2p1x1_8(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
|
||||
SYM(asm_c2p1x1_8):
|
||||
#ifdef __FASTCALL__
|
||||
| a0: chunky
|
||||
move.l a1,d0 | chunky end
|
||||
move.l 4(sp),a1 | screen
|
||||
#else
|
||||
move.l (4,sp),a0 | chunky
|
||||
move.l (8,sp),d0 | chunky end
|
||||
move.l (12,sp),a1 | screen
|
||||
#endif
|
||||
movem.l d2-d7/a2-a6,-(sp)
|
||||
move.l d0,a2
|
||||
move.l #0x0f0f0f0f,d4
|
||||
move.l #0x00ff00ff,d5
|
||||
move.l #0x55555555,d6
|
||||
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d3
|
||||
|
||||
| a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
|
||||
| e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
|
||||
| i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
|
||||
| m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d0,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d1
|
||||
move.l d3,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d2,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d2
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
|
||||
| a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
|
||||
| i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
|
||||
| i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d0,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d1,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d1
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
|
||||
| a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
|
||||
| b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
|
||||
| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
|
||||
|
||||
bra.s c2p1x1_8_start
|
||||
|
||||
c2p1x1_8_pix16:
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d3
|
||||
|
||||
| a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
|
||||
| e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
|
||||
| i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
|
||||
| m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #4,d7
|
||||
move.l a3,(a1)+
|
||||
eor.l d0,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d1
|
||||
move.l d3,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d2,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d2
|
||||
move.l a4,(a1)+
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
|
||||
| a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
|
||||
| i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
|
||||
| i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d0,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d0
|
||||
move.l a5,(a1)+
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d1,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d1
|
||||
move.l a6,(a1)+
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
|
||||
| a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
|
||||
| b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
|
||||
| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
|
||||
|
||||
c2p1x1_8_start:
|
||||
move.l d2,d7
|
||||
lsr.l #1,d7
|
||||
eor.l d0,d7
|
||||
and.l d6,d7
|
||||
eor.l d7,d0
|
||||
add.l d7,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #1,d7
|
||||
eor.l d1,d7
|
||||
and.l d6,d7
|
||||
eor.l d7,d1
|
||||
add.l d7,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
|
||||
| a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
|
||||
| a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.w d2,d7
|
||||
move.w d0,d2
|
||||
swap d2
|
||||
move.w d2,d0
|
||||
move.w d7,d2
|
||||
move.w d3,d7
|
||||
move.w d1,d3
|
||||
swap d3
|
||||
move.w d3,d1
|
||||
move.w d7,d3
|
||||
|
||||
| a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
|
||||
| c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
|
||||
| c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #2,d7
|
||||
eor.l d0,d7
|
||||
and.l #0x33333333,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #2,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #2,d7
|
||||
eor.l d1,d7
|
||||
and.l #0x33333333,d7
|
||||
eor.l d7,d1
|
||||
lsl.l #2,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7b7c7d7e7f7g7h7 i7j7k7l7m7n7o7p7 a6b6c6d6e6f6g6h6 i6j6k6l6m6n6o6p6
|
||||
| a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
|
||||
| a5b5c5d5e5f5g5h5 i5j5k5l5m5n5o5p5 a4b4c4d4e4f4g4h4 i4j4k4l4m4n4o4p4
|
||||
| a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
|
||||
|
||||
swap d0
|
||||
swap d1
|
||||
swap d2
|
||||
swap d3
|
||||
|
||||
move.l d0,a6
|
||||
move.l d2,a5
|
||||
move.l d1,a4
|
||||
move.l d3,a3
|
||||
|
||||
cmp.l a0,a2
|
||||
bne c2p1x1_8_pix16
|
||||
|
||||
move.l a3,(a1)+
|
||||
move.l a4,(a1)+
|
||||
move.l a5,(a1)+
|
||||
move.l a6,(a1)+
|
||||
|
||||
movem.l (sp)+,d2-d7/a2-a6
|
||||
rts
|
||||
|
||||
|
||||
| void asm_c2p1x1_8_tt(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen, uint32 screenPitch);
|
||||
SYM(asm_c2p1x1_8_tt):
|
||||
movem.l d2-d7/a2-a6,-(sp) | 6 + 5 = 11 longs
|
||||
|
||||
#ifdef __FASTCALL__
|
||||
| a0: chunky
|
||||
move.l a1,a2 | a2: chunky end
|
||||
move.l (11*4+4,sp),a1 | a1: screen
|
||||
| d0.l: screen pitch (double width)
|
||||
#else
|
||||
move.l (11*4+4,sp),a0 | a0: chunky
|
||||
move.l (11*4+8,sp),a2 | a2: chunky end
|
||||
move.l (11*4+12,sp),a1 | a1: screen
|
||||
move.l (11*4+16,sp),d0 | d0.l: screen pitch (double width)
|
||||
#endif
|
||||
move.l sp,old_sp
|
||||
|
||||
move.l d0,screen_pitch
|
||||
|
||||
lsr.l #1,d0
|
||||
lea (a1,d0.l),a7 | a7: end of first dst line
|
||||
|
||||
move.l d0,screen_offset
|
||||
|
||||
move.l #0x0f0f0f0f,d4
|
||||
move.l #0x00ff00ff,d5
|
||||
move.l #0x55555555,d6
|
||||
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d3
|
||||
|
||||
| a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
|
||||
| e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
|
||||
| i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
|
||||
| m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d0,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d1
|
||||
move.l d3,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d2,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d2
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
|
||||
| a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
|
||||
| i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
|
||||
| i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d0,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d1,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d1
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
|
||||
| a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
|
||||
| b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
|
||||
| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
|
||||
|
||||
bra.s c2p1x1_8_tt_start
|
||||
|
||||
c2p1x1_8_tt_pix16:
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d3
|
||||
|
||||
| a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
|
||||
| e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
|
||||
| i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
|
||||
| m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #4,d7
|
||||
move.l a3,(a1)+
|
||||
eor.l d0,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d1
|
||||
move.l d3,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d2,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d2
|
||||
move.l a4,(a1)+
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
|
||||
| a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
|
||||
| i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
|
||||
| i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d0,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d0
|
||||
move.l a5,(a1)+
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d1,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d1
|
||||
move.l a6,(a1)+
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
|
||||
| a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
|
||||
| b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
|
||||
| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
|
||||
|
||||
cmp.l a1,a7 | end of dst line?
|
||||
bne.s c2p1x1_8_tt_start
|
||||
|
||||
add.l (screen_offset,pc),a1
|
||||
add.l (screen_pitch,pc),a7
|
||||
|
||||
c2p1x1_8_tt_start:
|
||||
move.l d2,d7
|
||||
lsr.l #1,d7
|
||||
eor.l d0,d7
|
||||
and.l d6,d7
|
||||
eor.l d7,d0
|
||||
add.l d7,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #1,d7
|
||||
eor.l d1,d7
|
||||
and.l d6,d7
|
||||
eor.l d7,d1
|
||||
add.l d7,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
|
||||
| a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
|
||||
| a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.w d2,d7
|
||||
move.w d0,d2
|
||||
swap d2
|
||||
move.w d2,d0
|
||||
move.w d7,d2
|
||||
move.w d3,d7
|
||||
move.w d1,d3
|
||||
swap d3
|
||||
move.w d3,d1
|
||||
move.w d7,d3
|
||||
|
||||
| a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
|
||||
| c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
|
||||
| c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #2,d7
|
||||
eor.l d0,d7
|
||||
and.l #0x33333333,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #2,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #2,d7
|
||||
eor.l d1,d7
|
||||
and.l #0x33333333,d7
|
||||
eor.l d7,d1
|
||||
lsl.l #2,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7b7c7d7e7f7g7h7 i7j7k7l7m7n7o7p7 a6b6c6d6e6f6g6h6 i6j6k6l6m6n6o6p6
|
||||
| a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
|
||||
| a5b5c5d5e5f5g5h5 i5j5k5l5m5n5o5p5 a4b4c4d4e4f4g4h4 i4j4k4l4m4n4o4p4
|
||||
| a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
|
||||
|
||||
swap d0
|
||||
swap d1
|
||||
swap d2
|
||||
swap d3
|
||||
|
||||
move.l d0,a6
|
||||
move.l d2,a5
|
||||
move.l d1,a4
|
||||
move.l d3,a3
|
||||
|
||||
cmp.l a0,a2
|
||||
bne c2p1x1_8_tt_pix16
|
||||
|
||||
move.l a3,(a1)+
|
||||
move.l a4,(a1)+
|
||||
move.l a5,(a1)+
|
||||
move.l a6,(a1)+
|
||||
|
||||
move.l old_sp,sp
|
||||
movem.l (sp)+,d2-d7/a2-a6
|
||||
rts
|
||||
|
||||
|
||||
| void asm_c2p1x1_8_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
|
||||
SYM(asm_c2p1x1_8_rect):
|
||||
movem.l d2-d7/a2-a6,-(sp) | 6 + 5 = 11 longs
|
||||
|
||||
#ifdef __FASTCALL__
|
||||
| a0: chunky
|
||||
move.l a1,chunky_end
|
||||
| d0.l: chunky width
|
||||
move.l (11*4+4,sp),a1 | a1: screen
|
||||
exg d1,d2 | d2.l: chunky pitch
|
||||
| d1.l: screen pitch
|
||||
#else
|
||||
move.l (11*4+4,sp),a0 | a0: chunky
|
||||
move.l (11*4+8,sp),chunky_end
|
||||
move.l (11*4+12,sp),d0 | d0.l: chunky width
|
||||
move.l (11*4+16,sp),d2 | d2.l: chunky pitch
|
||||
move.l (11*4+20,sp),a1 | a1: screen
|
||||
move.l (11*4+24,sp),d1 | d1.l: screen pitch
|
||||
#endif
|
||||
move.l sp,old_sp
|
||||
|
||||
lea (a0,d0.l),a2 | a2: end of first src line
|
||||
lea (a1,d0.l),a7 | a7: end of first dst line
|
||||
|
||||
move.l d1,screen_pitch
|
||||
|
||||
sub.l d0,d1
|
||||
move.l d1,screen_offset
|
||||
|
||||
move.l d2,chunky_pitch
|
||||
|
||||
sub.l d0,d2
|
||||
move.l d2,chunky_offset
|
||||
|
||||
move.l #0x0f0f0f0f,d4
|
||||
move.l #0x00ff00ff,d5
|
||||
move.l #0x55555555,d6
|
||||
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d3
|
||||
|
||||
| a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
|
||||
| e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
|
||||
| i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
|
||||
| m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d0,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d1
|
||||
move.l d3,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d2,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d2
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
|
||||
| a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
|
||||
| i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
|
||||
| i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d0,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d1,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d1
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
|
||||
| a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
|
||||
| b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
|
||||
| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
|
||||
|
||||
bra.s c2p1x1_8_rect_start
|
||||
|
||||
c2p1x1_8_rect_pix16:
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d3
|
||||
|
||||
| a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
|
||||
| e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
|
||||
| i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
|
||||
| m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #4,d7
|
||||
move.l a3,(a1)+
|
||||
eor.l d0,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d1
|
||||
move.l d3,d7
|
||||
lsr.l #4,d7
|
||||
eor.l d2,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d2
|
||||
move.l a4,(a1)+
|
||||
lsl.l #4,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
|
||||
| a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
|
||||
| i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
|
||||
| i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d0,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d0
|
||||
move.l a5,(a1)+
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d1,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d1
|
||||
move.l a6,(a1)+
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
|
||||
| a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
|
||||
| b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
|
||||
| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
|
||||
|
||||
cmp.l a1,a7 | end of dst line?
|
||||
bne.s c2p1x1_8_rect_start
|
||||
|
||||
add.l (screen_offset,pc),a1
|
||||
add.l (screen_pitch,pc),a7
|
||||
|
||||
c2p1x1_8_rect_start:
|
||||
move.l d2,d7
|
||||
lsr.l #1,d7
|
||||
eor.l d0,d7
|
||||
and.l d6,d7
|
||||
eor.l d7,d0
|
||||
add.l d7,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #1,d7
|
||||
eor.l d1,d7
|
||||
and.l d6,d7
|
||||
eor.l d7,d1
|
||||
add.l d7,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
|
||||
| a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
|
||||
| a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.w d2,d7
|
||||
move.w d0,d2
|
||||
swap d2
|
||||
move.w d2,d0
|
||||
move.w d7,d2
|
||||
move.w d3,d7
|
||||
move.w d1,d3
|
||||
swap d3
|
||||
move.w d3,d1
|
||||
move.w d7,d3
|
||||
|
||||
| a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
|
||||
| c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
|
||||
| c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.l d2,d7
|
||||
lsr.l #2,d7
|
||||
eor.l d0,d7
|
||||
and.l #0x33333333,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #2,d7
|
||||
eor.l d7,d2
|
||||
move.l d3,d7
|
||||
lsr.l #2,d7
|
||||
eor.l d1,d7
|
||||
and.l #0x33333333,d7
|
||||
eor.l d7,d1
|
||||
lsl.l #2,d7
|
||||
eor.l d7,d3
|
||||
|
||||
| a7b7c7d7e7f7g7h7 i7j7k7l7m7n7o7p7 a6b6c6d6e6f6g6h6 i6j6k6l6m6n6o6p6
|
||||
| a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
|
||||
| a5b5c5d5e5f5g5h5 i5j5k5l5m5n5o5p5 a4b4c4d4e4f4g4h4 i4j4k4l4m4n4o4p4
|
||||
| a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
|
||||
|
||||
swap d0
|
||||
swap d1
|
||||
swap d2
|
||||
swap d3
|
||||
|
||||
move.l d0,a6
|
||||
move.l d2,a5
|
||||
move.l d1,a4
|
||||
move.l d3,a3
|
||||
|
||||
cmp.l a0,a2 | end of src line?
|
||||
bne c2p1x1_8_rect_pix16
|
||||
|
||||
cmp.l (chunky_end,pc),a2
|
||||
beq.s c2p1x1_8_rect_done
|
||||
|
||||
add.l (chunky_offset,pc),a0
|
||||
add.l (chunky_pitch,pc),a2
|
||||
|
||||
bra c2p1x1_8_rect_pix16
|
||||
|
||||
c2p1x1_8_rect_done:
|
||||
move.l a3,(a1)+
|
||||
move.l a4,(a1)+
|
||||
move.l a5,(a1)+
|
||||
move.l a6,(a1)+
|
||||
|
||||
move.l old_sp,sp
|
||||
movem.l (sp)+,d2-d7/a2-a6
|
||||
rts
|
||||
|
||||
|
||||
| void asm_c2p1x1_4(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
|
||||
SYM(asm_c2p1x1_4):
|
||||
#ifdef __FASTCALL__
|
||||
| a0: chunky
|
||||
move.l a1,d0 | chunky end
|
||||
move.l 4(sp),a1 | screen
|
||||
#else
|
||||
move.l (4,sp),a0 | chunky
|
||||
move.l (8,sp),d0 | chunky end
|
||||
move.l (12,sp),a1 | screen
|
||||
#endif
|
||||
movem.l d2-d7/a2-a6,-(sp)
|
||||
move.l d0,a2
|
||||
move.l #0x33333333,d4
|
||||
move.l #0x00ff00ff,d5
|
||||
move.l #0x55555555,d6
|
||||
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d3
|
||||
lsl.l #4,d0
|
||||
lsl.l #4,d1
|
||||
or.l d2,d0
|
||||
or.l d3,d1
|
||||
bra.s c2p1x1_4_start
|
||||
|
||||
c2p1x1_4_pix16:
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d3
|
||||
lsl.l #4,d0
|
||||
lsl.l #4,d1
|
||||
move.l a5,(a1)+
|
||||
or.l d2,d0
|
||||
or.l d3,d1
|
||||
move.l a6,(a1)+
|
||||
|
||||
c2p1x1_4_start:
|
||||
|
||||
| a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
|
||||
| i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d0,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d1
|
||||
|
||||
| a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
|
||||
| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #1,d7
|
||||
eor.l d0,d7
|
||||
and.l d6,d7
|
||||
eor.l d7,d0
|
||||
add.l d7,d7
|
||||
eor.l d7,d1
|
||||
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
|
||||
| a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.w d1,d7
|
||||
move.w d0,d1
|
||||
swap d1
|
||||
move.w d1,d0
|
||||
move.w d7,d1
|
||||
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
|
||||
| c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #2,d7
|
||||
eor.l d0,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #2,d7
|
||||
eor.l d7,d1
|
||||
|
||||
| a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
|
||||
| a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
|
||||
|
||||
swap d0
|
||||
swap d1
|
||||
|
||||
move.l d1,a5
|
||||
move.l d0,a6
|
||||
|
||||
cmp.l a0,a2
|
||||
bne.s c2p1x1_4_pix16
|
||||
|
||||
move.l a5,(a1)+
|
||||
move.l a6,(a1)+
|
||||
|
||||
movem.l (sp)+,d2-d7/a2-a6
|
||||
rts
|
||||
|
||||
|
||||
| void asm_c2p1x1_4_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
|
||||
SYM(asm_c2p1x1_4_rect):
|
||||
movem.l d2-d7/a2-a6,-(sp) | 6 + 5 = 11 longs
|
||||
|
||||
#ifdef __FASTCALL__
|
||||
| a0: chunky
|
||||
move.l a1,chunky_end
|
||||
| d0.l: chunky width
|
||||
move.l (11*4+4,sp),a1 | a1: screen
|
||||
exg d1,d2 | d2.l: chunky pitch
|
||||
| d1.l: screen pitch
|
||||
#else
|
||||
move.l (11*4+4,sp),a0 | a0: chunky
|
||||
move.l (11*4+8,sp),chunky_end
|
||||
move.l (11*4+12,sp),d0 | d0.l: chunky width
|
||||
move.l (11*4+16,sp),d2 | d2.l: chunky pitch
|
||||
move.l (11*4+20,sp),a1 | a1: screen
|
||||
move.l (11*4+24,sp),d1 | d1.l: screen pitch
|
||||
#endif
|
||||
move.l sp,old_sp
|
||||
|
||||
move.l d0,d3 | d3.l: screen width
|
||||
lsr.l #1,d3 |
|
||||
|
||||
lea (a0,d0.l),a2 | a2: end of first src line
|
||||
lea (a1,d3.l),a7 | a7: end of first dst line
|
||||
|
||||
move.l d1,screen_pitch
|
||||
|
||||
sub.l d3,d1
|
||||
move.l d1,screen_offset
|
||||
|
||||
move.l d2,chunky_pitch
|
||||
|
||||
sub.l d0,d2
|
||||
move.l d2,chunky_offset
|
||||
|
||||
move.l #0x33333333,d4
|
||||
move.l #0x00ff00ff,d5
|
||||
move.l #0x55555555,d6
|
||||
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d3
|
||||
lsl.l #4,d0
|
||||
lsl.l #4,d1
|
||||
or.l d2,d0
|
||||
or.l d3,d1
|
||||
bra.s c2p1x1_4_rect_start
|
||||
|
||||
c2p1x1_4_rect_pix16:
|
||||
move.l (a0)+,d0
|
||||
move.l (a0)+,d2
|
||||
move.l (a0)+,d1
|
||||
move.l (a0)+,d3
|
||||
lsl.l #4,d0
|
||||
lsl.l #4,d1
|
||||
move.l a5,(a1)+
|
||||
or.l d2,d0
|
||||
or.l d3,d1
|
||||
move.l a6,(a1)+
|
||||
|
||||
cmp.l a1,a7 | end of dst line?
|
||||
bne.s c2p1x1_4_rect_start
|
||||
|
||||
add.l (screen_offset,pc),a1
|
||||
add.l (screen_pitch,pc),a7
|
||||
|
||||
c2p1x1_4_rect_start:
|
||||
|
||||
| a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
|
||||
| i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #8,d7
|
||||
eor.l d0,d7
|
||||
and.l d5,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #8,d7
|
||||
eor.l d7,d1
|
||||
|
||||
| a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
|
||||
| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #1,d7
|
||||
eor.l d0,d7
|
||||
and.l d6,d7
|
||||
eor.l d7,d0
|
||||
add.l d7,d7
|
||||
eor.l d7,d1
|
||||
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
|
||||
| a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.w d1,d7
|
||||
move.w d0,d1
|
||||
swap d1
|
||||
move.w d1,d0
|
||||
move.w d7,d1
|
||||
|
||||
| a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
|
||||
| c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
|
||||
|
||||
move.l d1,d7
|
||||
lsr.l #2,d7
|
||||
eor.l d0,d7
|
||||
and.l d4,d7
|
||||
eor.l d7,d0
|
||||
lsl.l #2,d7
|
||||
eor.l d7,d1
|
||||
|
||||
| a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
|
||||
| a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
|
||||
|
||||
swap d0
|
||||
swap d1
|
||||
|
||||
move.l d1,a5
|
||||
move.l d0,a6
|
||||
|
||||
cmp.l a0,a2 | end of src line?
|
||||
bne.s c2p1x1_4_rect_pix16
|
||||
|
||||
cmp.l (chunky_end,pc),a2
|
||||
beq.s c2p1x1_4_rect_done
|
||||
|
||||
add.l (chunky_offset,pc),a0
|
||||
add.l (chunky_pitch,pc),a2
|
||||
|
||||
bra.s c2p1x1_4_rect_pix16
|
||||
|
||||
c2p1x1_4_rect_done:
|
||||
move.l a5,(a1)+
|
||||
move.l a6,(a1)+
|
||||
|
||||
move.l old_sp,sp
|
||||
movem.l (sp)+,d2-d7/a2-a6
|
||||
rts
|
||||
|
||||
|
||||
| place it within reach of 32K (PC relative)
|
||||
screen_pitch:
|
||||
ds.l 1
|
||||
screen_offset:
|
||||
ds.l 1
|
||||
chunky_pitch:
|
||||
ds.l 1
|
||||
chunky_offset:
|
||||
ds.l 1
|
||||
chunky_end:
|
||||
ds.l 1
|
||||
|
||||
.bss
|
||||
.even
|
||||
|
||||
old_sp: ds.l 1
|
||||
88
backends/graphics/atari/atari-c2p-asm.h
Normal file
88
backends/graphics/atari/atari-c2p-asm.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ATARI_C2P_ASM_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_C2P_ASM_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* Chunky to planar conversion routine. Converts a chunky (byte) buffer into eight bitplanes.
|
||||
* Optimized for surface-to-surface copy with the same pitch.
|
||||
*
|
||||
* @param pChunky chunky buffer start
|
||||
* @param pChunkyEnd chunky buffer end (past-the-end iterator)
|
||||
* @param pScreen bitplane screen start
|
||||
*/
|
||||
void asm_c2p1x1_8(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
|
||||
|
||||
/**
|
||||
* Chunky to planar conversion routine. Converts a chunky (byte) buffer into eight bitplanes.
|
||||
* Optimized for surface-to-surface copy with the double screen pitch (typically 320x480).
|
||||
*
|
||||
* @param pChunky chunky buffer start
|
||||
* @param pChunkyEnd chunky buffer end (past-the-end iterator)
|
||||
* @param pScreen bitplane screen start
|
||||
* @param screenPitch bitplane screen width (in bytes)
|
||||
*/
|
||||
void asm_c2p1x1_8_tt(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen, uint32 screenPitch);
|
||||
|
||||
/**
|
||||
* Chunky to planar conversion routine. Converts a chunky (byte) buffer into eight bitplanes.
|
||||
* Optimized for arbitrary rectangle position and dimension (16px aligned).
|
||||
*
|
||||
* @param pChunky chunky buffer at rectangle's [X1, Y1] position
|
||||
* @param pChunkyEnd chunky buffer at rectangle's [X2, Y2] position (included)
|
||||
* @param chunkyWidth rectangle width
|
||||
* @param chunkyPitch chunky buffer width (in bytes)
|
||||
* @param pScreen bitplane screen at rectangle's [X1, Y1] position
|
||||
* @param screenPitch bitplane screen width (in bytes)
|
||||
*/
|
||||
void asm_c2p1x1_8_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
|
||||
|
||||
/**
|
||||
* Chunky to planar conversion routine. Converts a chunky (byte) buffer into four bitplanes.
|
||||
* Optimized for surface-to-surface copy with the same pitch.
|
||||
*
|
||||
* @param pChunky chunky buffer start
|
||||
* @param pChunkyEnd chunky buffer end (past-the-end iterator)
|
||||
* @param pScreen bitplane screen start
|
||||
*/
|
||||
void asm_c2p1x1_4(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
|
||||
|
||||
/**
|
||||
* Chunky to planar conversion routine. Converts a chunky (byte) buffer into four bitplanes.
|
||||
* Optimized for arbitrary rectangle position and dimension (16px aligned).
|
||||
*
|
||||
* @param pChunky chunky buffer at rectangle's [X1, Y1] position
|
||||
* @param pChunkyEnd chunky buffer at rectangle's [X2, Y2] position (included)
|
||||
* @param chunkyWidth rectangle width
|
||||
* @param chunkyPitch chunky buffer width (in bytes)
|
||||
* @param pScreen bitplane screen at rectangle's [X1, Y1] position
|
||||
* @param screenPitch bitplane screen width (in bytes)
|
||||
*/
|
||||
void asm_c2p1x1_4_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
320
backends/graphics/atari/atari-cursor.cpp
Normal file
320
backends/graphics/atari/atari-cursor.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
/* 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 "atari-cursor.h"
|
||||
|
||||
#include "atari-supervidel.h"
|
||||
#include "atari-surface.h"
|
||||
//#include "backends/platform/atari/atari-debug.h"
|
||||
|
||||
bool Cursor::_globalSurfaceChanged;
|
||||
|
||||
byte Cursor::_palette[256*3];
|
||||
|
||||
const byte *Cursor::_buf;
|
||||
int Cursor::_width;
|
||||
int Cursor::_height;
|
||||
int Cursor::_hotspotX;
|
||||
int Cursor::_hotspotY;
|
||||
uint32 Cursor::_keycolor;
|
||||
|
||||
Graphics::Surface Cursor::_surface;
|
||||
Graphics::Surface Cursor::_surfaceMask;
|
||||
|
||||
Cursor::~Cursor() {
|
||||
_savedBackground.free();
|
||||
// beware, called multiple times (they have to be destroyed before
|
||||
// AtariSurfaceDeinit() is called)
|
||||
if (_surface.getPixels())
|
||||
_surface.free();
|
||||
if (_surface.getPixels())
|
||||
_surfaceMask.free();
|
||||
}
|
||||
|
||||
void Cursor::update() {
|
||||
if (!_buf) {
|
||||
_outOfScreen = true;
|
||||
_savedRect = _alignedDstRect = Common::Rect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_visible || (!_positionChanged && !_surfaceChanged))
|
||||
return;
|
||||
|
||||
_srcRect = Common::Rect(_width, _height);
|
||||
|
||||
_dstRect = Common::Rect(
|
||||
_x - _hotspotX, // left
|
||||
_y - _hotspotY, // top
|
||||
_x - _hotspotX + _width, // right
|
||||
_y - _hotspotY + _height); // bottom
|
||||
|
||||
_outOfScreen = !_boundingSurf->clip(_srcRect, _dstRect);
|
||||
|
||||
if (!_outOfScreen) {
|
||||
assert(_srcRect.width() == _dstRect.width());
|
||||
assert(_srcRect.height() == _dstRect.height());
|
||||
|
||||
const int dstBitsPerPixel = _screenSurf->getBitsPerPixel();
|
||||
const int xOffset = (_screenSurf->w - _boundingSurf->w) / 2;
|
||||
|
||||
// non-direct rendering never uses 4bpp but maybe in the future ...
|
||||
_savedRect = AtariSurface::alignRect(
|
||||
_dstRect.left * dstBitsPerPixel / 8, // fake 4bpp by 8bpp's x/2
|
||||
_dstRect.top,
|
||||
_dstRect.right * dstBitsPerPixel / 8, // fake 4bpp by 8bpp's width/2
|
||||
_dstRect.bottom);
|
||||
|
||||
// this is used only in flushBackground() for comparison with rects
|
||||
// passed by Screen::addDirtyRect (aligned and shifted by the same offset)
|
||||
_alignedDstRect = AtariSurface::alignRect(
|
||||
_dstRect.left + xOffset,
|
||||
_dstRect.top,
|
||||
_dstRect.right + xOffset,
|
||||
_dstRect.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
void Cursor::updatePosition(int deltaX, int deltaY) {
|
||||
//atari_debug("Cursor::updatePosition: %d, %d", deltaX, deltaX);
|
||||
|
||||
if (deltaX == 0 && deltaY == 0)
|
||||
return;
|
||||
|
||||
_x += deltaX;
|
||||
_y += deltaY;
|
||||
|
||||
if (_x < 0)
|
||||
_x = 0;
|
||||
else if (_x >= _boundingSurf->w)
|
||||
_x = _boundingSurf->w - 1;
|
||||
|
||||
if (_y < 0)
|
||||
_y = 0;
|
||||
else if (_y >= _boundingSurf->h)
|
||||
_y = _boundingSurf->h - 1;
|
||||
|
||||
_positionChanged = true;
|
||||
}
|
||||
|
||||
/* static */ void Cursor::setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor) {
|
||||
if (w == 0 || h == 0 || buf == nullptr) {
|
||||
_buf = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
_buf = (const byte *)buf;
|
||||
_width = w;
|
||||
_height = h;
|
||||
_hotspotX = hotspotX;
|
||||
_hotspotY = hotspotY;
|
||||
_keycolor = keycolor;
|
||||
|
||||
_globalSurfaceChanged = true;
|
||||
}
|
||||
|
||||
/* static */ void Cursor::setPalette(const byte *colors, uint start, uint num) {
|
||||
memcpy(&_palette[start * 3], colors, num * 3);
|
||||
|
||||
_globalSurfaceChanged = true;
|
||||
}
|
||||
|
||||
/* static */ void Cursor::convertSurfaceTo(const Graphics::PixelFormat &format) {
|
||||
static int rShift, gShift, bShift;
|
||||
static int rMask, gMask, bMask;
|
||||
|
||||
const int cursorWidth = g_hasSuperVidel ? _width : ((_width + 15) & (-16));
|
||||
const int cursorHeight = _height;
|
||||
const bool isCLUT8 = format.isCLUT8();
|
||||
|
||||
if (_surface.w != cursorWidth || _surface.h != cursorHeight || _surface.format != format) {
|
||||
if (!isCLUT8 && _surface.format != format) {
|
||||
rShift = format.rLoss - format.rShift;
|
||||
gShift = format.gLoss - format.gShift;
|
||||
bShift = format.bLoss - format.bShift;
|
||||
|
||||
rMask = format.rMax() << format.rShift;
|
||||
gMask = format.gMax() << format.gShift;
|
||||
bMask = format.bMax() << format.bShift;
|
||||
}
|
||||
|
||||
// always 8-bit as this is both 8-bit src and 4-bit dst for C2P
|
||||
_surface.create(cursorWidth, cursorHeight, format);
|
||||
assert(_surface.pitch == _surface.w);
|
||||
// always 8-bit or 1-bit
|
||||
_surfaceMask.create(g_hasSuperVidel ? _surface.w : _surface.w / 8, _surface.h, PIXELFORMAT_CLUT8);
|
||||
_surfaceMask.w = _surface.w;
|
||||
}
|
||||
|
||||
const byte *src = _buf;
|
||||
byte *dst = (byte *)_surface.getPixels();
|
||||
byte *dstMask = (byte *)_surfaceMask.getPixels();
|
||||
uint16 *dstMask16 = (uint16 *)_surfaceMask.getPixels();
|
||||
const int dstPadding = _surface.w - _width;
|
||||
|
||||
uint16 mask16 = 0xffff;
|
||||
uint16 invertedBit = 0x7fff;
|
||||
|
||||
for (int j = 0; j < _height; ++j) {
|
||||
for (int i = 0; i < _width; ++i) {
|
||||
const uint32 color = *src++;
|
||||
|
||||
if (color != _keycolor) {
|
||||
if (!isCLUT8) {
|
||||
// Convert CLUT8 to RGB332/RGB121 palette
|
||||
*dst++ = ((_palette[color*3 + 0] >> rShift) & rMask)
|
||||
| ((_palette[color*3 + 1] >> gShift) & gMask)
|
||||
| ((_palette[color*3 + 2] >> bShift) & bMask);
|
||||
} else {
|
||||
*dst++ = color;
|
||||
}
|
||||
|
||||
if (g_hasSuperVidel)
|
||||
*dstMask++ = 0xff;
|
||||
else
|
||||
mask16 &= invertedBit;
|
||||
} else {
|
||||
*dst++ = 0x00;
|
||||
|
||||
if (g_hasSuperVidel)
|
||||
*dstMask++ = 0x00;
|
||||
}
|
||||
|
||||
if (!g_hasSuperVidel && invertedBit == 0xfffe) {
|
||||
*dstMask16++ = mask16;
|
||||
mask16 = 0xffff;
|
||||
}
|
||||
|
||||
// ror.w #1,invertedBit
|
||||
invertedBit = (invertedBit >> 1) | (invertedBit << (sizeof (invertedBit) * 8 - 1));
|
||||
}
|
||||
|
||||
if (dstPadding) {
|
||||
assert(!g_hasSuperVidel);
|
||||
|
||||
// this is at most 15 pixels
|
||||
memset(dst, 0x00, dstPadding);
|
||||
dst += dstPadding;
|
||||
|
||||
*dstMask16++ = mask16;
|
||||
mask16 = 0xffff;
|
||||
invertedBit = 0x7fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect Cursor::flushBackground(const Common::Rect &alignedRect, bool directRendering) {
|
||||
if (_savedRect.isEmpty())
|
||||
return _savedRect;
|
||||
|
||||
if (!alignedRect.isEmpty() && alignedRect.contains(_alignedDstRect)) {
|
||||
// better would be _visibilityChanged but update() ignores it
|
||||
_positionChanged = true;
|
||||
|
||||
_savedRect = Common::Rect();
|
||||
} else if (alignedRect.isEmpty() || alignedRect.intersects(_alignedDstRect)) {
|
||||
// better would be _visibilityChanged but update() ignores it
|
||||
_positionChanged = true;
|
||||
|
||||
if (directRendering)
|
||||
restoreBackground();
|
||||
else
|
||||
return _alignedDstRect;
|
||||
}
|
||||
|
||||
return Common::Rect();
|
||||
}
|
||||
|
||||
void Cursor::saveBackground() {
|
||||
if (_savedRect.isEmpty())
|
||||
return;
|
||||
|
||||
// as this is used only for direct rendering, we don't need to worry about offsettedSurf
|
||||
// having different dimensions than the source surface
|
||||
const Graphics::Surface &dstSurface = *_screenSurf;
|
||||
|
||||
//atari_debug("Cursor::saveBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
|
||||
|
||||
// save native bitplanes or pixels, so it must be a Graphics::Surface to copy from
|
||||
if (_savedBackground.w != _savedRect.width()
|
||||
|| _savedBackground.h != _savedRect.height()
|
||||
|| _savedBackground.format != dstSurface.format) {
|
||||
_savedBackground.create(_savedRect.width(), _savedRect.height(), dstSurface.format);
|
||||
}
|
||||
|
||||
_savedBackground.copyRectToSurface(dstSurface, 0, 0, _savedRect);
|
||||
}
|
||||
|
||||
void Cursor::draw() {
|
||||
AtariSurface &dstSurface = *_screenSurf;
|
||||
const int dstBitsPerPixel = dstSurface.getBitsPerPixel();
|
||||
|
||||
//atari_debug("Cursor::draw: %d %d %d %d", _dstRect.left, _dstRect.top, _dstRect.width(), _dstRect.height());
|
||||
|
||||
if (_globalSurfaceChanged) {
|
||||
convertSurfaceTo(dstSurface.format);
|
||||
|
||||
if (!g_hasSuperVidel) {
|
||||
// C2P in-place
|
||||
AtariSurface surf;
|
||||
surf.w = _surface.w;
|
||||
surf.h = _surface.h;
|
||||
surf.pitch = _surface.pitch * dstBitsPerPixel / 8; // 4bpp is not byte per pixel anymore
|
||||
surf.setPixels(_surface.getPixels());
|
||||
surf.format = _surface.format;
|
||||
|
||||
surf.copyRectToSurface(
|
||||
_surface,
|
||||
0, 0,
|
||||
Common::Rect(_surface.w, _surface.h));
|
||||
}
|
||||
|
||||
_globalSurfaceChanged = false;
|
||||
}
|
||||
|
||||
dstSurface.drawMaskedSprite(
|
||||
_surface, _surfaceMask, *_boundingSurf,
|
||||
_dstRect.left, _dstRect.top,
|
||||
_srcRect);
|
||||
|
||||
_visibilityChanged = _positionChanged = _surfaceChanged = false;
|
||||
}
|
||||
|
||||
void Cursor::restoreBackground() {
|
||||
if (_savedRect.isEmpty())
|
||||
return;
|
||||
|
||||
assert(_savedBackground.getPixels());
|
||||
|
||||
//atari_debug("Cursor::restoreBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
|
||||
|
||||
// as this is used only for direct rendering, we don't need to worry about offsettedSurf
|
||||
// having different dimensions than the source surface
|
||||
Graphics::Surface &dstSurface = *_screenSurf->surfacePtr();
|
||||
|
||||
// restore native bitplanes or pixels, so it must be a Graphics::Surface to copy to
|
||||
dstSurface.copyRectToSurface(
|
||||
_savedBackground,
|
||||
_savedRect.left, _savedRect.top,
|
||||
Common::Rect(_savedBackground.w, _savedBackground.h));
|
||||
|
||||
_savedRect = Common::Rect();
|
||||
}
|
||||
140
backends/graphics/atari/atari-cursor.h
Normal file
140
backends/graphics/atari/atari-cursor.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ATARI_CURSOR_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_CURSOR_H
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
class AtariSurface;
|
||||
|
||||
// Global state consists of:
|
||||
// - palette (used for the overlay only atm)
|
||||
// - shape (surface, dimensions, hotspot, keycolor)
|
||||
// - visibility
|
||||
// These always get updates by ScummVM, no need to differentiate between engines and the overlay.
|
||||
|
||||
struct Cursor {
|
||||
~Cursor();
|
||||
|
||||
void reset(AtariSurface* screenSurf, const Graphics::Surface *boundingSurf) {
|
||||
_screenSurf = screenSurf;
|
||||
_boundingSurf = boundingSurf;
|
||||
|
||||
_positionChanged = true;
|
||||
_surfaceChanged = true;
|
||||
_visibilityChanged = false;
|
||||
|
||||
_savedRect = _alignedDstRect = Common::Rect();
|
||||
}
|
||||
|
||||
// updates outOfScreen OR srcRect/dstRect (only if visible/needed)
|
||||
void update();
|
||||
|
||||
// visibility
|
||||
bool setVisible(bool visible) {
|
||||
if (_visible == visible) {
|
||||
return _visible;
|
||||
}
|
||||
|
||||
bool last = _visible;
|
||||
|
||||
_visible = visible;
|
||||
|
||||
_visibilityChanged = true;
|
||||
|
||||
return last;
|
||||
}
|
||||
void setSurfaceChanged() {
|
||||
_surfaceChanged = true;
|
||||
}
|
||||
|
||||
// position
|
||||
Common::Point getPosition() const {
|
||||
return Common::Point(_x, _y);
|
||||
}
|
||||
void setPosition(int x, int y) {
|
||||
//atari_debug("Cursor::setPosition: %d, %d", x, y);
|
||||
|
||||
if (_x == x && _y == y)
|
||||
return;
|
||||
|
||||
_x = x;
|
||||
_y = y;
|
||||
|
||||
_positionChanged = true;
|
||||
}
|
||||
void updatePosition(int deltaX, int deltaY);
|
||||
|
||||
// surface
|
||||
static void setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor);
|
||||
static void setPalette(const byte *colors, uint start, uint num);
|
||||
|
||||
bool isVisible() const {
|
||||
return !_outOfScreen && _visible;
|
||||
}
|
||||
bool isChanged() const {
|
||||
return _positionChanged || _surfaceChanged || _visibilityChanged;
|
||||
}
|
||||
|
||||
Common::Rect flushBackground(const Common::Rect &alignedRect, bool directRendering);
|
||||
void saveBackground();
|
||||
void draw();
|
||||
|
||||
private:
|
||||
static void convertSurfaceTo(const Graphics::PixelFormat &format);
|
||||
void restoreBackground();
|
||||
|
||||
AtariSurface *_screenSurf;
|
||||
const Graphics::Surface *_boundingSurf = nullptr;
|
||||
|
||||
bool _positionChanged = false;
|
||||
bool _surfaceChanged = false;
|
||||
bool _visibilityChanged = false;
|
||||
|
||||
bool _visible = false;
|
||||
int _x = 0;
|
||||
int _y = 0;
|
||||
bool _outOfScreen = true;
|
||||
Common::Rect _srcRect;
|
||||
Common::Rect _dstRect;
|
||||
|
||||
Graphics::Surface _savedBackground;
|
||||
Common::Rect _savedRect;
|
||||
Common::Rect _alignedDstRect;
|
||||
|
||||
// related to 'surface'
|
||||
static bool _globalSurfaceChanged;
|
||||
|
||||
static byte _palette[256*3];
|
||||
|
||||
static const byte *_buf;
|
||||
static int _width;
|
||||
static int _height;
|
||||
static int _hotspotX;
|
||||
static int _hotspotY;
|
||||
static uint32 _keycolor;
|
||||
|
||||
static Graphics::Surface _surface;
|
||||
static Graphics::Surface _surfaceMask;
|
||||
};
|
||||
|
||||
#endif // BACKENDS_GRAPHICS_ATARI_CURSOR_H
|
||||
510
backends/graphics/atari/atari-graphics-asm.S
Normal file
510
backends/graphics/atari/atari-graphics-asm.S
Normal file
@@ -0,0 +1,510 @@
|
||||
/* 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 "../../platform/atari/symbols.h"
|
||||
|
||||
.global SYM(asm_draw_4bpl_sprite)
|
||||
.global SYM(asm_draw_8bpl_sprite)
|
||||
|
||||
.text
|
||||
|
||||
skip_first_pix16:
|
||||
dc.b 0
|
||||
skip_last_pix16:
|
||||
dc.b 0
|
||||
|
||||
| extern void asm_draw_4bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint16 *srcMask,
|
||||
| uint destX, uint destY, uint dstPitch, uint srcPitch, uint w, uint h,
|
||||
| bool skipFirstPix16, bool skipLastPix16);
|
||||
SYM(asm_draw_4bpl_sprite):
|
||||
movem.l d2-d7/a2,-(sp) | 7 longs
|
||||
|
||||
#ifdef __FASTCALL__
|
||||
move.l a0,a2 | a2: dstBuffer
|
||||
| a1: srcBuffer
|
||||
move.l (4+7*4,sp),a0 | a0: srcMask
|
||||
| d0.w: destX
|
||||
| d1.w: destY
|
||||
move.l d2,d3 | d3.w: dstPitch
|
||||
move.l (8+7*4,sp),d4 | d4.w: srcPitch
|
||||
move.l (12+7*4,sp),d6 | d6.w: w
|
||||
move.l (16+7*4,sp),d7 | d7.w: h
|
||||
tst.l (20+7*4,sp) | skipFirstPix16?
|
||||
sne skip_first_pix16
|
||||
tst.l (24+7*4,sp) | skipLastPix16?
|
||||
sne skip_last_pix16
|
||||
#else
|
||||
move.l (4+7*4,sp),a2 | a2: dstBuffer
|
||||
move.l (8+7*4,sp),a1 | a1: srcBuffer
|
||||
move.l (12+7*4,sp),a0 | a0: srcMask
|
||||
move.l (16+7*4,sp),d0 | d0.w: destX
|
||||
move.l (20+7*4,sp),d1 | d1.w: destY
|
||||
move.l (24+7*4,sp),d3 | d3.w: dstPitch
|
||||
move.l (28+7*4,sp),d4 | d4.w: srcPitch
|
||||
move.l (32+7*4,sp),d6 | d6.w: w
|
||||
move.l (36+7*4,sp),d7 | d7.w: h
|
||||
tst.l (40+7*4,sp) | skipFirstPix16?
|
||||
sne skip_first_pix16
|
||||
tst.l (44+7*4,sp) | skipLastPix16?
|
||||
sne skip_last_pix16
|
||||
#endif
|
||||
|
||||
| Draws a 4 bitplane sprite at any position on screen.
|
||||
| (c) 1999 Pieter van der Meer (EarX)
|
||||
|
|
||||
| INPUT: d0.w: x position of sprite on screen (left side)
|
||||
| d1.w: y position of sprite on screen (top side)
|
||||
| d6.w: number of 16pixel X blocks to do
|
||||
| d7.w: number of Y lines to to
|
||||
| a0: address of maskdata
|
||||
| a1: address of bitmapdata
|
||||
| a2: screen start address
|
||||
|
||||
move.w d0,d2 | / Calculate the
|
||||
andi.w #0b111111110000,d0 | | number of bits
|
||||
sub.w d0,d2 | \ to shift right.
|
||||
lsr.w #1,d0 | / Add x-position to
|
||||
adda.w d0,a2 | \ screenaddress.
|
||||
mulu.w d3,d1 | / Add y-position to
|
||||
adda.l d1,a2 | \ screenaddress.
|
||||
lsr.w #1,d6
|
||||
sub.w d6,d3 | / Prepare offset to next
|
||||
ext.l d3 | \ destination line.
|
||||
sub.w d6,d4 | / Prepare offset to next
|
||||
ext.l d4 | \ source line.
|
||||
subq.w #1,d7 | Adjust for dbra.
|
||||
lsr.w #3,d6 | d6.w: w/16
|
||||
subq.w #1,d6 | Adjust for dbra.
|
||||
move.w d6,d5 | Backup xloopcount in d5.w.
|
||||
|
||||
tst.b (skip_first_pix16,pc)
|
||||
jeq 1f
|
||||
subq.w #1,d5
|
||||
1:
|
||||
tst.b (skip_last_pix16,pc)
|
||||
jeq 2f
|
||||
subq.w #1,d5
|
||||
2:
|
||||
sprite4_yloop:
|
||||
move.w d5,d6 | Restore xloop counter.
|
||||
|
||||
tst.b (skip_first_pix16,pc)
|
||||
jeq 1f
|
||||
|
||||
moveq #16,d1
|
||||
sub.w d2,d1
|
||||
|
||||
moveq #0xffffffff,d0 | Prepare for maskshifting.
|
||||
move.w (a0)+,d0 | Get 16pixel mask in d0.w.
|
||||
rol.l d1,d0 | Shift it!
|
||||
addq.l #8,a2
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 0.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 1.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 2.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 3.
|
||||
subq.l #8,a2 | Return to blockstart.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 0.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 1.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 2.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 3.
|
||||
|
||||
subq.l #8,a2
|
||||
|
||||
1: tst.w d6
|
||||
jmi sprite4_xloop_done
|
||||
|
||||
sprite4_xloop:
|
||||
moveq #0xffffffff,d0 | Prepare for maskshifting.
|
||||
move.w (a0)+,d0 | Get 16pixel mask in d0.w.
|
||||
ror.l d2,d0 | Shift it!
|
||||
and.w d0,(a2)+ | Mask bitplane 0.
|
||||
and.w d0,(a2)+ | Mask bitplane 1.
|
||||
and.w d0,(a2)+ | Mask bitplane 2.
|
||||
and.w d0,(a2)+ | Mask bitplane 3.
|
||||
swap d0 | Get overspill in loword.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 0.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 1.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 2.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 3.
|
||||
lea (-16,a2),a2 | Return to blockstart.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 0.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,6(a2) | Paint overspill bitplane 0.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 1.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,6(a2) | Paint overspill bitplane 1.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 2.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,6(a2) | Paint overspill bitplane 2.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 3.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,6(a2) | Paint overspill bitplane 3.
|
||||
|
||||
dbra d6,sprite4_xloop | Loop until blocks done.
|
||||
|
||||
sprite4_xloop_done:
|
||||
tst.b (skip_last_pix16,pc)
|
||||
jeq 1f
|
||||
|
||||
moveq #0xffffffff,d0 | Prepare for maskshifting.
|
||||
move.w (a0)+,d0 | Get 16pixel mask in d0.w.
|
||||
ror.l d2,d0 | Shift it!
|
||||
and.w d0,(a2)+ | Mask bitplane 0.
|
||||
and.w d0,(a2)+ | Mask bitplane 1.
|
||||
and.w d0,(a2)+ | Mask bitplane 2.
|
||||
and.w d0,(a2)+ | Mask bitplane 3.
|
||||
subq.l #8,a2 | Return to blockstart.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 0.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 1.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 2.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 3.
|
||||
|
||||
1: move.l d4,d0
|
||||
asr.l #2,d0
|
||||
adda.l d0,a0
|
||||
adda.l d4,a1
|
||||
adda.l d3,a2 | Goto next screenline.
|
||||
dbra d7,sprite4_yloop | Loop until lines done.
|
||||
|
||||
movem.l (sp)+,d2-d7/a2
|
||||
rts
|
||||
|
||||
| extern void asm_draw_8bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint16 *srcMask,
|
||||
| uint destX, uint destY, uint dstPitch, uint srcPitch, uint w, uint h,
|
||||
| bool skipFirstPix16, bool skipLastPix16);
|
||||
SYM(asm_draw_8bpl_sprite):
|
||||
movem.l d2-d7/a2,-(sp) | 7 longs
|
||||
|
||||
#ifdef __FASTCALL__
|
||||
move.l a0,a2 | a2: dstBuffer
|
||||
| a1: srcBuffer
|
||||
move.l (4+7*4,sp),a0 | a0: srcMask
|
||||
| d0.w: destX
|
||||
| d1.w: destY
|
||||
move.l d2,d3 | d3.w: dstPitch
|
||||
move.l (8+7*4,sp),d4 | d4.w: srcPitch
|
||||
move.l (12+7*4,sp),d6 | d6.w: w
|
||||
move.l (16+7*4,sp),d7 | d7.w: h
|
||||
tst.l (20+7*4,sp) | skipFirstPix16?
|
||||
sne skip_first_pix16
|
||||
tst.l (24+7*4,sp) | skipLastPix16?
|
||||
sne skip_last_pix16
|
||||
#else
|
||||
move.l (4+7*4,sp),a2 | a2: dstBuffer
|
||||
move.l (8+7*4,sp),a1 | a1: srcBuffer
|
||||
move.l (12+7*4,sp),a0 | a0: srcMask
|
||||
move.l (16+7*4,sp),d0 | d0.w: destX
|
||||
move.l (20+7*4,sp),d1 | d1.w: destY
|
||||
move.l (24+7*4,sp),d3 | d3.w: dstPitch
|
||||
move.l (28+7*4,sp),d4 | d4.w: srcPitch
|
||||
move.l (32+7*4,sp),d6 | d6.w: w
|
||||
move.l (36+7*4,sp),d7 | d7.w: h
|
||||
tst.l (40+7*4,sp) | skipFirstPix16?
|
||||
sne skip_first_pix16
|
||||
tst.l (45+7*4,sp) | skipLastPix16?
|
||||
sne skip_last_pix16
|
||||
#endif
|
||||
move.w d0,d2 | / Calculate the
|
||||
andi.w #0b111111110000,d0 | | number of bits
|
||||
sub.w d0,d2 | \ to shift right.
|
||||
adda.w d0,a2 | Add x-position to screenaddress.
|
||||
mulu.w d3,d1 | / Add y-position to
|
||||
adda.l d1,a2 | \ screenaddress.
|
||||
sub.w d6,d3 | / Prepare offset to next
|
||||
ext.l d3 | \ destination line.
|
||||
sub.w d6,d4 | / Prepare offset to next
|
||||
ext.l d4 | \ source line.
|
||||
subq.w #1,d7 | Adjust for dbra.
|
||||
lsr.w #4,d6 | d6.w: w/16
|
||||
subq.w #1,d6 | Adjust for dbra.
|
||||
move.w d6,d5 | Backup xloopcount in d5.w.
|
||||
|
||||
tst.b (skip_first_pix16,pc)
|
||||
jeq 1f
|
||||
subq.w #1,d5
|
||||
1:
|
||||
tst.b (skip_last_pix16,pc)
|
||||
jeq 2f
|
||||
subq.w #1,d5
|
||||
2:
|
||||
sprite8_yloop:
|
||||
move.w d5,d6 | Restore xloop counter.
|
||||
|
||||
tst.b (skip_first_pix16,pc)
|
||||
jeq 1f
|
||||
|
||||
moveq #16,d1
|
||||
sub.w d2,d1
|
||||
|
||||
moveq #0xffffffff,d0 | Prepare for maskshifting.
|
||||
move.w (a0)+,d0 | Get 16pixel mask in d0.w.
|
||||
rol.l d1,d0 | Shift it!
|
||||
lea (16,a2),a2
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 0.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 1.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 2.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 3.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 4.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 5.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 6.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 7.
|
||||
lea (-16,a2),a2 | Return to blockstart.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 0.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 1.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 2.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 3.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 4.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 5.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 6.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
rol.l d1,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint overspill bitplane 7.
|
||||
|
||||
lea (-16,a2),a2
|
||||
|
||||
1: tst.w d6
|
||||
jmi sprite8_xloop_done
|
||||
|
||||
sprite8_xloop:
|
||||
moveq #0xffffffff,d0 | Prepare for maskshifting.
|
||||
move.w (a0)+,d0 | Get 16pixel mask in d0.w.
|
||||
ror.l d2,d0 | Shift it!
|
||||
and.w d0,(a2)+ | Mask bitplane 0.
|
||||
and.w d0,(a2)+ | Mask bitplane 1.
|
||||
and.w d0,(a2)+ | Mask bitplane 2.
|
||||
and.w d0,(a2)+ | Mask bitplane 3.
|
||||
and.w d0,(a2)+ | Mask bitplane 4.
|
||||
and.w d0,(a2)+ | Mask bitplane 5.
|
||||
and.w d0,(a2)+ | Mask bitplane 6.
|
||||
and.w d0,(a2)+ | Mask bitplane 7.
|
||||
swap d0 | Get overspill in loword.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 0.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 1.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 2.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 3.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 4.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 5.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 6.
|
||||
and.w d0,(a2)+ | Mask overspill bitplane 7.
|
||||
lea (-32,a2),a2 | Return to blockstart.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 0.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,14(a2) | Paint overspill bitplane 0.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 1.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,14(a2) | Paint overspill bitplane 1.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 2.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,14(a2) | Paint overspill bitplane 2.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 3.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,14(a2) | Paint overspill bitplane 3.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 4.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,14(a2) | Paint overspill bitplane 4.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 5.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,14(a2) | Paint overspill bitplane 5.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 6.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,14(a2) | Paint overspill bitplane 6.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 7.
|
||||
swap d0 | Get overspill in loword.
|
||||
or.w d0,14(a2) | Paint overspill bitplane 7.
|
||||
|
||||
dbra d6,sprite8_xloop | Loop until blocks done.
|
||||
|
||||
sprite8_xloop_done:
|
||||
tst.b (skip_last_pix16,pc)
|
||||
jeq 1f
|
||||
|
||||
moveq #0xffffffff,d0 | Prepare for maskshifting.
|
||||
move.w (a0)+,d0 | Get 16pixel mask in d0.w.
|
||||
ror.l d2,d0 | Shift it!
|
||||
and.w d0,(a2)+ | Mask bitplane 0.
|
||||
and.w d0,(a2)+ | Mask bitplane 1.
|
||||
and.w d0,(a2)+ | Mask bitplane 2.
|
||||
and.w d0,(a2)+ | Mask bitplane 3.
|
||||
and.w d0,(a2)+ | Mask bitplane 4.
|
||||
and.w d0,(a2)+ | Mask bitplane 5.
|
||||
and.w d0,(a2)+ | Mask bitplane 6.
|
||||
and.w d0,(a2)+ | Mask bitplane 7.
|
||||
lea (-16,a2),a2 | Return to blockstart.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 0.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 1.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 2.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 3.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 4.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 5.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 6.
|
||||
|
||||
moveq #0,d0 | Prepare for bitmapshifting.
|
||||
move.w (a1)+,d0 | Get bitplaneword in d0.w.
|
||||
ror.l d2,d0 | Shift it.
|
||||
or.w d0,(a2)+ | Paint bitplane 7.
|
||||
|
||||
1: move.l d4,d0
|
||||
asr.l #3,d0
|
||||
adda.l d0,a0
|
||||
adda.l d4,a1
|
||||
adda.l d3,a2 | Goto next screenline.
|
||||
dbra d7,sprite8_yloop | Loop until lines done.
|
||||
|
||||
movem.l (sp)+,d2-d7/a2
|
||||
rts
|
||||
68
backends/graphics/atari/atari-graphics-asm.h
Normal file
68
backends/graphics/atari/atari-graphics-asm.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ATARI_ASM_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_ASM_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* Copy 4bpl sprite into 4bpl buffer. Sprite's width must be multiply of 16.
|
||||
*
|
||||
* @param dstBuffer destination buffer (four bitplanes)
|
||||
* @param srcBuffer source buffer (four bitplanes)
|
||||
* @param srcMask source mask (one bitplane)
|
||||
* @param destX sprite's X position (in pixels)
|
||||
* @param destY sprite's Y position (in pixels)
|
||||
* @param dstPitch destination buffer's pitch (in bytes)
|
||||
* @param srcPitch source buffer's pitch (in bytes)
|
||||
* @param w sprite's width (in pixels)
|
||||
* @param h sprite's height (in pixels)
|
||||
* @param skipFirstPix16 do not write first 16 pixels
|
||||
* @param skipLastPix16 do not write last 16 pixels
|
||||
*/
|
||||
void asm_draw_4bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint16 *srcMask,
|
||||
uint destX, uint destY, uint dstPitch, uint srcPitch, uint w, uint h,
|
||||
bool skipFirstPix16, bool skipLastPix16);
|
||||
/**
|
||||
* Copy 8bpl sprite into 8bpl buffer. Sprite's width must be multiply of 16.
|
||||
*
|
||||
* @param dstBuffer destination buffer (eight bitplanes)
|
||||
* @param srcBuffer source buffer (eight bitplanes)
|
||||
* @param srcMask source mask (one bitplane)
|
||||
* @param destX sprite's X position (in pixels)
|
||||
* @param destY sprite's Y position (in pixels)
|
||||
* @param dstPitch destination buffer's pitch (in bytes)
|
||||
* @param srcPitch source buffer's pitch (in bytes)
|
||||
* @param w sprite's width (in pixels)
|
||||
* @param h sprite's height (in pixels)
|
||||
* @param skipFirstPix16 do not write first 16 pixels
|
||||
* @param skipLastPix16 do not write last 16 pixels
|
||||
*/
|
||||
void asm_draw_8bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint16 *srcMask,
|
||||
uint destX, uint destY, uint dstPitch, uint srcPitch, uint w, uint h,
|
||||
bool skipFirstPix16, bool skipLastPix16);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
1153
backends/graphics/atari/atari-graphics.cpp
Normal file
1153
backends/graphics/atari/atari-graphics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
213
backends/graphics/atari/atari-graphics.h
Normal file
213
backends/graphics/atari/atari-graphics.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ATARI_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_H
|
||||
|
||||
#include "backends/graphics/graphics.h"
|
||||
#include "common/events.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "atari-cursor.h"
|
||||
#include "atari-pendingscreenchanges.h"
|
||||
#include "atari-screen.h"
|
||||
#include "atari-supervidel.h"
|
||||
|
||||
#define MAX_HZ_SHAKE 16 // Falcon only
|
||||
#define MAX_V_SHAKE 16
|
||||
|
||||
class AtariGraphicsManager final : public GraphicsManager, Common::EventObserver {
|
||||
friend class PendingScreenChanges;
|
||||
|
||||
public:
|
||||
AtariGraphicsManager();
|
||||
virtual ~AtariGraphicsManager();
|
||||
|
||||
bool hasFeature(OSystem::Feature f) const override;
|
||||
void setFeatureState(OSystem::Feature f, bool enable) override;
|
||||
bool getFeatureState(OSystem::Feature f) const override;
|
||||
|
||||
const OSystem::GraphicsMode *getSupportedGraphicsModes() const override {
|
||||
static const OSystem::GraphicsMode graphicsModes[] = {
|
||||
{ "direct", "Direct rendering", kDirectRendering },
|
||||
{ "single", "Single buffering", kSingleBuffering },
|
||||
{ "triple", "Triple buffering", kTripleBuffering },
|
||||
{ nullptr, nullptr, 0 }
|
||||
};
|
||||
return graphicsModes;
|
||||
}
|
||||
int getDefaultGraphicsMode() const override { return kTripleBuffering; }
|
||||
bool setGraphicsMode(int mode, uint flags = OSystem::kGfxModeNoFlags) override;
|
||||
int getGraphicsMode() const override { return _currentState.mode; }
|
||||
|
||||
void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) override;
|
||||
|
||||
int getScreenChangeID() const override { return 0; }
|
||||
|
||||
void beginGFXTransaction() override;
|
||||
OSystem::TransactionError endGFXTransaction() override;
|
||||
|
||||
int16 getHeight() const override { return _currentState.height; }
|
||||
int16 getWidth() const override { return _currentState.width; }
|
||||
void setPalette(const byte *colors, uint start, uint num) override;
|
||||
void grabPalette(byte *colors, uint start, uint num) const override;
|
||||
void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override;
|
||||
Graphics::Surface *lockScreen() override;
|
||||
void unlockScreen() override;
|
||||
void fillScreen(uint32 col) override;
|
||||
void fillScreen(const Common::Rect &r, uint32 col) override;
|
||||
void updateScreen() override;
|
||||
void setShakePos(int shakeXOffset, int shakeYOffset) override;
|
||||
void setFocusRectangle(const Common::Rect& rect) override {}
|
||||
void clearFocusRectangle() override {}
|
||||
|
||||
void showOverlay(bool inGUI) override;
|
||||
void hideOverlay() override;
|
||||
bool isOverlayVisible() const override { return _overlayState == kOverlayVisible; }
|
||||
Graphics::PixelFormat getOverlayFormat() const override;
|
||||
void clearOverlay() override;
|
||||
void grabOverlay(Graphics::Surface &surface) const override;
|
||||
void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
|
||||
int16 getOverlayHeight() const override { return 480; }
|
||||
int16 getOverlayWidth() const override { return _vgaMonitor ? 640 : 640*1.2; }
|
||||
|
||||
bool showMouse(bool visible) override;
|
||||
void warpMouse(int x, int y) override;
|
||||
void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor,
|
||||
bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override;
|
||||
void setCursorPalette(const byte *colors, uint start, uint num) override;
|
||||
|
||||
Common::Point getMousePosition() const {
|
||||
if (isOverlayVisible()) {
|
||||
return _screen[kOverlayBuffer]->cursor.getPosition();
|
||||
} else {
|
||||
// kFrontBuffer is always up to date
|
||||
return _screen[kFrontBuffer]->cursor.getPosition();
|
||||
}
|
||||
}
|
||||
void updateMousePosition(int deltaX, int deltaY);
|
||||
|
||||
bool notifyEvent(const Common::Event &event) override;
|
||||
Common::Keymap *getKeymap() const;
|
||||
|
||||
private:
|
||||
enum {
|
||||
kUnknownMode = -1,
|
||||
kDirectRendering = 0,
|
||||
kSingleBuffering = 1,
|
||||
kTripleBuffering = 3
|
||||
};
|
||||
|
||||
enum CustomEventAction {
|
||||
kActionToggleAspectRatioCorrection = 100,
|
||||
};
|
||||
|
||||
void allocateSurfaces();
|
||||
void freeSurfaces();
|
||||
|
||||
#ifndef DISABLE_FANCY_THEMES
|
||||
int16 getMaximumScreenHeight() const { return 480; }
|
||||
int16 getMaximumScreenWidth() const { return _tt ? 320 : (_vgaMonitor ? 640 : 640*1.2); }
|
||||
#else
|
||||
int16 getMaximumScreenHeight() const { return _tt ? 480 : 240; }
|
||||
int16 getMaximumScreenWidth() const { return _tt ? 320 : (_vgaMonitor ? 320 : 320*1.2); }
|
||||
#endif
|
||||
|
||||
void addDirtyRectToScreens(const Graphics::Surface &dstSurface,
|
||||
int x, int y, int w, int h, bool directRendering);
|
||||
bool updateScreenInternal(Screen *dstScreen, const Graphics::Surface *srcSurface);
|
||||
void copyRectToAtariSurface(AtariSurface &dstSurface,
|
||||
const byte *buf, int pitch, int x, int y, int w, int h);
|
||||
|
||||
bool isOverlayDirectRendering() const {
|
||||
#ifndef DISABLE_FANCY_THEMES
|
||||
// see osystem_atari.cpp
|
||||
extern bool g_gameEngineActive;
|
||||
#endif
|
||||
// overlay is direct rendered if in the launcher or if game is directly rendered
|
||||
// (on SuperVidel we always want to use _overlaySurface as source for background pixels)
|
||||
return !g_hasSuperVidel
|
||||
#ifndef DISABLE_FANCY_THEMES
|
||||
&& (!g_gameEngineActive || _currentState.mode == kDirectRendering)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
Graphics::Surface *lockOverlay();
|
||||
|
||||
bool _vgaMonitor = true;
|
||||
bool _tt = false;
|
||||
|
||||
struct GraphicsState {
|
||||
GraphicsState()
|
||||
: inTransaction(false)
|
||||
, mode(kUnknownMode)
|
||||
, width(0)
|
||||
, height(0)
|
||||
, format(Graphics::PixelFormat()) {
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return mode != kUnknownMode && width > 0 && height > 0 && format.bytesPerPixel != 0;
|
||||
}
|
||||
|
||||
bool inTransaction;
|
||||
int mode;
|
||||
int width;
|
||||
int height;
|
||||
Graphics::PixelFormat format;
|
||||
};
|
||||
GraphicsState _pendingState;
|
||||
GraphicsState _currentState;
|
||||
|
||||
// feature flags
|
||||
bool _aspectRatioCorrection = false;
|
||||
|
||||
PendingScreenChanges _pendingScreenChanges;
|
||||
|
||||
enum {
|
||||
kFrontBuffer = 0,
|
||||
kBackBuffer1 = 1,
|
||||
kBackBuffer2 = 2,
|
||||
kOverlayBuffer = 3,
|
||||
kBufferCount
|
||||
};
|
||||
Screen *_screen[kBufferCount] = {};
|
||||
|
||||
Graphics::Surface _chunkySurface;
|
||||
Graphics::Surface _chunkySurfaceOffsetted;
|
||||
|
||||
enum {
|
||||
kOverlayVisible,
|
||||
kOverlayIgnoredHide,
|
||||
kOverlayHidden
|
||||
};
|
||||
int _overlayState = kOverlayHidden;
|
||||
bool _ignoreHideOverlay = true;
|
||||
Graphics::Surface _overlaySurface;
|
||||
bool _ignoreCursorChanges = false;
|
||||
|
||||
Palette _palette;
|
||||
Palette _overlayPalette;
|
||||
};
|
||||
|
||||
#endif
|
||||
157
backends/graphics/atari/atari-pendingscreenchanges.cpp
Normal file
157
backends/graphics/atari/atari-pendingscreenchanges.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/* 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 "atari-pendingscreenchanges.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <mint/falcon.h>
|
||||
|
||||
#include "backends/platform/atari/atari-debug.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "atari-graphics.h"
|
||||
#include "atari-supervidel.h"
|
||||
|
||||
void PendingScreenChanges::queueAll() {
|
||||
_changes |= kAll;
|
||||
|
||||
if (_manager->_tt)
|
||||
_changes &= ~kAspectRatioCorrection;
|
||||
}
|
||||
|
||||
/*
|
||||
* VsetRGB() - stores the palette in a buffer and process it in the nearest non-locked VBL
|
||||
* EsetPalette() - immediatelly applies the palette
|
||||
* (V)SetScreen() - immediatelly sets physbase/logbase but explicitly calls Vsync() for resolution changes
|
||||
* VsetMode() - explicitly calls Vsync()
|
||||
*/
|
||||
|
||||
void PendingScreenChanges::applyBeforeVblLock(const Screen &screen) {
|
||||
_mode = screen.mode; // avoid modifying 'Screen' content
|
||||
_resetSuperVidel = false;
|
||||
|
||||
_aspectRatioCorrectionYOffset.second = false;
|
||||
_setScreenOffsets.second = false;
|
||||
_shrinkVidelVisibleArea.second = false;
|
||||
|
||||
if (_changes & kAspectRatioCorrection) {
|
||||
processAspectRatioCorrection(screen);
|
||||
_changes &= ~kAspectRatioCorrection;
|
||||
}
|
||||
|
||||
_switchToBlackPalette = (_changes & kVideoMode) || _resetSuperVidel;
|
||||
|
||||
if (_changes & kVideoMode) {
|
||||
processVideoMode(screen);
|
||||
// don't reset kVideoMode yet
|
||||
}
|
||||
}
|
||||
|
||||
void PendingScreenChanges::applyAfterVblLock(const Screen &screen) {
|
||||
// VBL doesn't process new palette nor screen address updates
|
||||
// if _changes & kVideoMode then the Vsync handler has just returned
|
||||
|
||||
if (_changes & kShakeScreen) {
|
||||
_setScreenOffsets = std::make_pair(true, true);
|
||||
_changes &= ~kShakeScreen;
|
||||
}
|
||||
|
||||
// restore current (kVideoMode) or set new (kPalette) palette
|
||||
if (_changes & (kVideoMode | kPalette)) {
|
||||
if (_switchToBlackPalette || (_changes & kPalette)) {
|
||||
// Set the palette as fast as possible. Vsync() is a big no-no, updateScreen() and
|
||||
// therefore this function can be called multiple times per frame. In this case,
|
||||
// EsetPalette() will set the colours immediately (oops) but VsetRGB() is fine:
|
||||
// it will be set as soon as VBL is unlocked again.
|
||||
if (_manager->_tt) {
|
||||
EsetPalette(0, screen.palette->entries, screen.palette->tt);
|
||||
} else {
|
||||
VsetRGB(0, screen.palette->entries, screen.palette->falcon);
|
||||
}
|
||||
}
|
||||
|
||||
_changes &= ~(kVideoMode | kPalette);
|
||||
}
|
||||
|
||||
assert(_changes == kNone);
|
||||
}
|
||||
|
||||
void PendingScreenChanges::processAspectRatioCorrection(const Screen &screen) {
|
||||
assert(!_manager->_tt);
|
||||
assert(_mode != -1);
|
||||
|
||||
if (_manager->_aspectRatioCorrection && _manager->_currentState.height == 200 && !_manager->isOverlayVisible()) {
|
||||
// apply machine-specific aspect ratio correction
|
||||
if (!_manager->_vgaMonitor) {
|
||||
_mode &= ~PAL;
|
||||
// 60 Hz
|
||||
_mode |= NTSC;
|
||||
_changes |= kVideoMode;
|
||||
} else {
|
||||
_aspectRatioCorrectionYOffset =
|
||||
std::make_pair((screen.surf->h - 2*MAX_V_SHAKE - screen.offsettedSurf->h) / 2, true);
|
||||
_shrinkVidelVisibleArea = std::make_pair(true, true);
|
||||
}
|
||||
} else {
|
||||
// reset back to default mode
|
||||
if (!_manager->_vgaMonitor) {
|
||||
_mode &= ~NTSC;
|
||||
// 50 Hz
|
||||
_mode |= PAL;
|
||||
_changes |= kVideoMode;
|
||||
} else {
|
||||
_aspectRatioCorrectionYOffset = std::make_pair(0, true);
|
||||
_shrinkVidelVisibleArea = std::make_pair(false, true);
|
||||
|
||||
if (g_hasSuperVidel)
|
||||
_resetSuperVidel = true;
|
||||
|
||||
// kPendingVideoMode will reset the shrunken Videl area
|
||||
_changes |= kVideoMode;
|
||||
}
|
||||
}
|
||||
|
||||
// for VsetMode() and/or _aspectRatioCorrectionYOffset
|
||||
_setScreenOffsets = std::make_pair(true, true);
|
||||
}
|
||||
|
||||
void PendingScreenChanges::processVideoMode(const Screen &screen) {
|
||||
// changing video mode implies an additional Vsync(): there's no way to change resolution
|
||||
// and set new screen address (and/or shake offsets etc) in one go
|
||||
if (screen.rez != -1) {
|
||||
static uint16 black[256];
|
||||
EsetPalette(0, screen.palette->entries, black);
|
||||
|
||||
// unfortunately this reinitializes VDI, too
|
||||
Setscreen(SCR_NOCHANGE, SCR_NOCHANGE, screen.rez);
|
||||
} else if (_mode != -1) {
|
||||
static _RGB black[256];
|
||||
VsetRGB(0, screen.palette->entries, black);
|
||||
|
||||
// VsetMode() must be called before the VBL s_ stuff is set as
|
||||
// it resets all hz/v, scrolling and line width registers
|
||||
if (_resetSuperVidel)
|
||||
VsetMode(SVEXT | SVEXT_BASERES(0) | COL80 | BPS8C); // resync to proper 640x480
|
||||
|
||||
atari_debug("VsetMode: %04x", _mode);
|
||||
VsetMode(_mode);
|
||||
}
|
||||
}
|
||||
111
backends/graphics/atari/atari-pendingscreenchanges.h
Normal file
111
backends/graphics/atari/atari-pendingscreenchanges.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ATARI_PENDINGSCREENCHANGES_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_PENDINGSCREENCHANGES_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
class AtariGraphicsManager;
|
||||
class AtariSurface;
|
||||
class Screen;
|
||||
|
||||
class PendingScreenChanges {
|
||||
public:
|
||||
PendingScreenChanges(const AtariGraphicsManager *manager)
|
||||
: _manager(manager) {
|
||||
}
|
||||
|
||||
void clearTransaction() {
|
||||
_changes &= ~kTransaction;
|
||||
}
|
||||
|
||||
void setScreenSurface(AtariSurface *surface) {
|
||||
_surface = surface;
|
||||
}
|
||||
|
||||
void queueVideoMode() {
|
||||
_changes |= kVideoMode;
|
||||
}
|
||||
void queueAspectRatioCorrection() {
|
||||
_changes |= kAspectRatioCorrection;
|
||||
}
|
||||
void queuePalette() {
|
||||
_changes |= kPalette;
|
||||
}
|
||||
void queueShakeScreen() {
|
||||
_changes |= kShakeScreen;
|
||||
}
|
||||
void queueAll();
|
||||
|
||||
int get() const {
|
||||
return _changes;
|
||||
}
|
||||
bool empty() const {
|
||||
return _changes == kNone;
|
||||
}
|
||||
|
||||
AtariSurface *screenSurface() const {
|
||||
return _surface;
|
||||
}
|
||||
const std::pair<int, bool>& aspectRatioCorrectionYOffset() const {
|
||||
return _aspectRatioCorrectionYOffset;
|
||||
}
|
||||
const std::pair<bool, bool>& screenOffsets() const {
|
||||
return _setScreenOffsets;
|
||||
}
|
||||
const std::pair<bool, bool>& shrinkVidelVisibleArea() const {
|
||||
return _shrinkVidelVisibleArea;
|
||||
}
|
||||
|
||||
void applyBeforeVblLock(const Screen &screen);
|
||||
void applyAfterVblLock(const Screen &screen);
|
||||
|
||||
private:
|
||||
void processAspectRatioCorrection(const Screen &screen);
|
||||
void processVideoMode(const Screen &screen);
|
||||
|
||||
enum Change {
|
||||
kNone = 0,
|
||||
kVideoMode = 1<<0,
|
||||
kAspectRatioCorrection = 1<<1,
|
||||
kPalette = 1<<2,
|
||||
kShakeScreen = 1<<3,
|
||||
kTransaction = kVideoMode | kAspectRatioCorrection,
|
||||
kAll = kTransaction | kPalette | kShakeScreen
|
||||
};
|
||||
int _changes = kNone;
|
||||
|
||||
const AtariGraphicsManager *_manager;
|
||||
|
||||
AtariSurface *_surface = nullptr;
|
||||
|
||||
int _mode;
|
||||
bool _resetSuperVidel;
|
||||
bool _switchToBlackPalette;
|
||||
|
||||
// <value, set> ... std::optional would be so much better!
|
||||
std::pair<int, bool> _aspectRatioCorrectionYOffset;
|
||||
std::pair<bool, bool> _setScreenOffsets;
|
||||
std::pair<bool, bool> _shrinkVidelVisibleArea;
|
||||
};
|
||||
|
||||
#endif // ATARI-PENDINGSCREENCHANGES_H
|
||||
170
backends/graphics/atari/atari-screen.cpp
Normal file
170
backends/graphics/atari/atari-screen.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/* 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 "atari-screen.h"
|
||||
|
||||
#include <mint/falcon.h>
|
||||
|
||||
#include "atari-graphics.h" // MAX_HZ_SHAKE, MAX_V_SHAKE
|
||||
#include "atari-supervidel.h" // g_hasSuperVidel
|
||||
//#include "backends/platform/atari/atari-debug.h"
|
||||
|
||||
Screen::Screen(bool tt, int width, int height, const Graphics::PixelFormat &format, const Palette *palette_)
|
||||
: palette(palette_)
|
||||
, _tt(tt) {
|
||||
|
||||
#ifdef USE_SUPERVIDEL
|
||||
if (g_hasSuperVidel) {
|
||||
surf.reset(new SuperVidelSurface(
|
||||
width + 2 * MAX_HZ_SHAKE,
|
||||
height + 2 * MAX_V_SHAKE,
|
||||
format));
|
||||
_offsettedSurf.reset(new SuperVidelSurface());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
surf.reset(new AtariSurface(
|
||||
width + (_tt ? 0 : 2 * MAX_HZ_SHAKE),
|
||||
height + 2 * MAX_V_SHAKE,
|
||||
format));
|
||||
_offsettedSurf.reset(new AtariSurface());
|
||||
}
|
||||
|
||||
_offsettedSurf->create(
|
||||
*surf,
|
||||
Common::Rect(
|
||||
Common::Point(
|
||||
(surf->w - width) / 2, // left
|
||||
(surf->h - height) / 2), // top
|
||||
width, height));
|
||||
}
|
||||
|
||||
void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf) {
|
||||
clearDirtyRects();
|
||||
|
||||
rez = -1;
|
||||
mode = -1;
|
||||
|
||||
const int bitsPerPixel = surf->getBitsPerPixel();
|
||||
|
||||
// erase old screen
|
||||
_offsettedSurf->fillRect(_offsettedSurf->getBounds(), 0);
|
||||
|
||||
if (_tt) {
|
||||
if (width <= 320 && height <= 240) {
|
||||
surf->w = 320;
|
||||
surf->h = 240 + 2 * MAX_V_SHAKE;
|
||||
surf->pitch = 2 * surf->w * bitsPerPixel / 8;
|
||||
rez = kRezValueTTLow;
|
||||
} else {
|
||||
surf->w = 640;
|
||||
surf->h = 480 + 2 * MAX_V_SHAKE;
|
||||
surf->pitch = surf->w * bitsPerPixel / 8;
|
||||
rez = kRezValueTTMid;
|
||||
}
|
||||
} else {
|
||||
mode = VsetMode(VM_INQUIRE) & PAL;
|
||||
|
||||
if (VgetMonitor() == MON_VGA) {
|
||||
mode |= VGA | (bitsPerPixel == 4 ? BPS4 : (g_hasSuperVidel ? BPS8C : BPS8));
|
||||
|
||||
if (width <= 320 && height <= 240) {
|
||||
surf->w = 320;
|
||||
surf->h = 240;
|
||||
mode |= VERTFLAG | COL40;
|
||||
} else {
|
||||
surf->w = 640;
|
||||
surf->h = 480;
|
||||
mode |= COL80;
|
||||
}
|
||||
} else {
|
||||
mode |= TV | (bitsPerPixel == 4 ? BPS4 : BPS8);
|
||||
|
||||
if (width <= 320 && height <= 200) {
|
||||
surf->w = 320;
|
||||
surf->h = 200;
|
||||
mode |= COL40;
|
||||
} else if (width <= 320*1.2 && height <= 200*1.2) {
|
||||
surf->w = 320*1.2;
|
||||
surf->h = 200*1.2;
|
||||
mode |= OVERSCAN | COL40;
|
||||
} else if (width <= 640 && height <= 400) {
|
||||
surf->w = 640;
|
||||
surf->h = 400;
|
||||
mode |= VERTFLAG | COL80;
|
||||
} else {
|
||||
surf->w = 640*1.2;
|
||||
surf->h = 400*1.2;
|
||||
mode |= VERTFLAG | OVERSCAN | COL80;
|
||||
}
|
||||
}
|
||||
|
||||
surf->w += 2 * MAX_HZ_SHAKE;
|
||||
surf->h += 2 * MAX_V_SHAKE;
|
||||
surf->pitch = surf->w * bitsPerPixel / 8;
|
||||
}
|
||||
|
||||
_offsettedSurf->create(
|
||||
*surf,
|
||||
Common::Rect(
|
||||
Common::Point(
|
||||
(surf->w - width) / 2, // left
|
||||
(surf->h - height) / 2), // top
|
||||
width, height));
|
||||
|
||||
cursor.reset(_offsettedSurf.get(), &boundingSurf);
|
||||
cursor.setPosition(boundingSurf.w / 2, boundingSurf.h / 2);
|
||||
}
|
||||
|
||||
void Screen::addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int w, int h, bool directRendering) {
|
||||
if (fullRedraw)
|
||||
return;
|
||||
|
||||
if ((w == srcSurface.w && h == srcSurface.h)
|
||||
|| dirtyRects.size() == 128) { // 320x200 can hold at most 250 16x16 rectangles
|
||||
//atari_debug("addDirtyRect[%d]: purge %d x %d", (int)dirtyRects.size(), srcSurface.w, srcSurface.h);
|
||||
|
||||
dirtyRects.clear();
|
||||
// even if srcSurface.w != _offsettedSurf.w, alignRect would lead to the same result
|
||||
dirtyRects.insert(_offsettedSurf->getBounds());
|
||||
|
||||
cursor.reset(_offsettedSurf.get(), &srcSurface);
|
||||
|
||||
fullRedraw = true;
|
||||
} else {
|
||||
// x,y are relative to srcSurface but screen's width is always aligned to 16 bytes
|
||||
// so both dirty rects and cursor must be drawn in screen coordinates
|
||||
const int xOffset = (_offsettedSurf->w - srcSurface.w) / 2;
|
||||
|
||||
const Common::Rect alignedRect = AtariSurface::alignRect(x + xOffset, y, x + xOffset + w, y + h);
|
||||
|
||||
dirtyRects.insert(alignedRect);
|
||||
|
||||
// Check whether the cursor background intersects the dirty rect. Has to be done here,
|
||||
// before the actual drawing (especially in case of direct rendering). There's one more
|
||||
// check in AtariGraphicsManager::updateScreenInternal for the case when there are no
|
||||
// dirty rectangles but the cursor itself has changed.
|
||||
const Common::Rect cursorBackgroundRect = cursor.flushBackground(alignedRect, directRendering);
|
||||
if (!cursorBackgroundRect.isEmpty()) {
|
||||
dirtyRects.insert(cursorBackgroundRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
backends/graphics/atari/atari-screen.h
Normal file
99
backends/graphics/atari/atari-screen.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ATARI_SCREEN_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_SCREEN_H
|
||||
|
||||
#include <unordered_set>
|
||||
#include <mint/ostruct.h> // _RGB
|
||||
|
||||
#include "common/ptr.h"
|
||||
|
||||
#include "atari-cursor.h"
|
||||
#include "atari-surface.h"
|
||||
|
||||
template<>
|
||||
struct std::hash<Common::Rect>
|
||||
{
|
||||
std::size_t operator()(Common::Rect const& rect) const noexcept
|
||||
{
|
||||
return 31 * (31 * (31 * rect.left + rect.top) + rect.right) + rect.bottom;
|
||||
}
|
||||
};
|
||||
|
||||
class Palette {
|
||||
public:
|
||||
void clear() {
|
||||
memset(_data, 0, sizeof(_data));
|
||||
entries = 0;
|
||||
}
|
||||
|
||||
uint16 *const tt = reinterpret_cast<uint16*>(_data);
|
||||
_RGB *const falcon = reinterpret_cast<_RGB*>(_data);
|
||||
|
||||
int entries = 0;
|
||||
|
||||
private:
|
||||
byte _data[256*4] = {};
|
||||
};
|
||||
|
||||
struct Screen {
|
||||
using DirtyRects = std::unordered_set<Common::Rect>;
|
||||
|
||||
Screen(bool tt, int width, int height, const Graphics::PixelFormat &format, const Palette *palette);
|
||||
|
||||
void reset(int width, int height, const Graphics::Surface &boundingSurf);
|
||||
// must be called before any rectangle drawing
|
||||
void addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int w, int h, bool directRendering);
|
||||
|
||||
void clearDirtyRects() {
|
||||
dirtyRects.clear();
|
||||
fullRedraw = false;
|
||||
}
|
||||
|
||||
Common::ScopedPtr<AtariSurface> surf;
|
||||
const Palette *palette;
|
||||
DirtyRects dirtyRects;
|
||||
bool fullRedraw = false;
|
||||
|
||||
Cursor cursor;
|
||||
|
||||
int rez = -1;
|
||||
int mode = -1;
|
||||
const Common::ScopedPtr<AtariSurface> &offsettedSurf = _offsettedSurf;
|
||||
|
||||
private:
|
||||
static constexpr size_t ALIGN = 16; // 16 bytes
|
||||
|
||||
enum SteTtRezValue {
|
||||
kRezValueSTLow = 0, // 320x200@4bpp, ST palette
|
||||
kRezValueSTMid = 1, // 640x200@2bpp, ST palette
|
||||
kRezValueSTHigh = 2, // 640x400@1bpp, ST palette
|
||||
kRezValueTTLow = 7, // 320x480@8bpp, TT palette
|
||||
kRezValueTTMid = 4, // 640x480@4bpp, TT palette
|
||||
kRezValueTTHigh = 6 // 1280x960@1bpp, TT palette
|
||||
};
|
||||
|
||||
bool _tt;
|
||||
Common::ScopedPtr<AtariSurface> _offsettedSurf;
|
||||
};
|
||||
|
||||
#endif // BACKENDS_GRAPHICS_ATARI_SCREEN_H
|
||||
67
backends/graphics/atari/atari-supervidel.cpp
Normal file
67
backends/graphics/atari/atari-supervidel.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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 "atari-supervidel.h"
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
bool g_hasSuperVidel = false;
|
||||
|
||||
#ifdef USE_SUPERVIDEL
|
||||
|
||||
#ifdef USE_SV_BLITTER
|
||||
int g_superVidelFwVersion = 0;
|
||||
const byte *g_blitMask = nullptr;
|
||||
|
||||
static bool isSuperBlitterLocked;
|
||||
|
||||
void SyncSuperBlitter() {
|
||||
// if externally locked, let the owner decide when to sync (unlock)
|
||||
if (isSuperBlitterLocked)
|
||||
return;
|
||||
|
||||
// while FIFO not empty...
|
||||
if (g_superVidelFwVersion >= 9)
|
||||
while (!(*SV_BLITTER_FIFO & 1));
|
||||
// while busy blitting...
|
||||
while (*SV_BLITTER_CONTROL & 1);
|
||||
}
|
||||
#endif // USE_SV_BLITTER
|
||||
|
||||
void LockSuperBlitter() {
|
||||
#ifdef USE_SV_BLITTER
|
||||
assert(!isSuperBlitterLocked);
|
||||
|
||||
isSuperBlitterLocked = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void UnlockSuperBlitter() {
|
||||
#ifdef USE_SV_BLITTER
|
||||
assert(isSuperBlitterLocked);
|
||||
|
||||
isSuperBlitterLocked = false;
|
||||
if (g_hasSuperVidel)
|
||||
SyncSuperBlitter();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // USE_SUPERVIDEL
|
||||
70
backends/graphics/atari/atari-supervidel.h
Normal file
70
backends/graphics/atari/atari-supervidel.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#ifdef USE_SUPERVIDEL
|
||||
|
||||
// bits 26:0
|
||||
#define SV_BLITTER_SRC1 ((volatile long *)0x80010058)
|
||||
#define SV_BLITTER_SRC2 ((volatile long *)0x8001005C)
|
||||
#define SV_BLITTER_DST ((volatile long *)0x80010060)
|
||||
// The amount of bytes that are to be copied in a horizontal line, minus 1
|
||||
#define SV_BLITTER_COUNT ((volatile long *)0x80010064)
|
||||
// The amount of bytes that are to be added to the line start address after a line has been copied, in order to reach the next one
|
||||
#define SV_BLITTER_SRC1_OFFSET ((volatile long *)0x80010068)
|
||||
#define SV_BLITTER_SRC2_OFFSET ((volatile long *)0x8001006C)
|
||||
#define SV_BLITTER_DST_OFFSET ((volatile long *)0x80010070)
|
||||
// bits 11:0 - The amount of horizontal lines to do
|
||||
#define SV_BLITTER_MASK_AND_LINES ((volatile long *)0x80010074)
|
||||
// bit 0 - busy / start
|
||||
// bits 4:1 - blit mode
|
||||
#define SV_BLITTER_CONTROL ((volatile long *)0x80010078)
|
||||
// bits 9:0
|
||||
#define SV_VERSION ((volatile long *)0x8001007C)
|
||||
// bit 0 - empty (read only)
|
||||
// bit 1 - full (read only)
|
||||
// bits 31:0 - data (write only)
|
||||
#define SV_BLITTER_FIFO ((volatile long *)0x80010080)
|
||||
|
||||
#ifdef USE_SV_BLITTER
|
||||
extern int g_superVidelFwVersion;
|
||||
extern const byte *g_blitMask;
|
||||
|
||||
void SyncSuperBlitter();
|
||||
#endif // USE_SV_BLITTER
|
||||
|
||||
void LockSuperBlitter();
|
||||
void UnlockSuperBlitter();
|
||||
|
||||
#else
|
||||
|
||||
static inline void LockSuperBlitter() {}
|
||||
static inline void UnlockSuperBlitter() {}
|
||||
|
||||
#endif // USE_SUPERVIDEL
|
||||
|
||||
extern bool g_hasSuperVidel;
|
||||
|
||||
#endif // BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
|
||||
346
backends/graphics/atari/atari-surface.cpp
Normal file
346
backends/graphics/atari/atari-surface.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
/* 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 "atari-surface.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include <mint/cookie.h>
|
||||
#include <mint/falcon.h>
|
||||
#include <mint/trap14.h>
|
||||
#define ct60_vm(mode, value) (long)trap_14_wwl((short)0xc60e, (short)(mode), (long)(value))
|
||||
#define ct60_vmalloc(value) ct60_vm(0, value)
|
||||
#define ct60_vmfree(value) ct60_vm(1, value)
|
||||
|
||||
#include "backends/graphics/atari/atari-c2p-asm.h"
|
||||
#include "backends/graphics/atari/atari-graphics-asm.h"
|
||||
#include "backends/graphics/atari/atari-supervidel.h"
|
||||
#include "backends/platform/atari/atari-debug.h"
|
||||
#include "backends/platform/atari/dlmalloc.h"
|
||||
#include "common/textconsole.h" // error()
|
||||
|
||||
static struct MemoryPool {
|
||||
void create() {
|
||||
if (base)
|
||||
_mspace = create_mspace_with_base((void *)base, size, 0);
|
||||
|
||||
if (_mspace)
|
||||
atari_debug("Allocated mspace at 0x%08lx (%ld bytes)", base, size);
|
||||
else
|
||||
error("mspace allocation failed at 0x%08lx (%ld bytes)", base, size);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (_mspace) {
|
||||
destroy_mspace(_mspace);
|
||||
_mspace = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void *malloc(size_t bytes) {
|
||||
assert(_mspace);
|
||||
return mspace_malloc(_mspace, bytes);
|
||||
}
|
||||
|
||||
void *calloc(size_t n_elements, size_t elem_size) {
|
||||
assert(_mspace);
|
||||
return mspace_calloc(_mspace, n_elements, elem_size);
|
||||
}
|
||||
|
||||
void free(void *mem) {
|
||||
assert(_mspace);
|
||||
mspace_free(_mspace, mem);
|
||||
}
|
||||
|
||||
long base;
|
||||
long size;
|
||||
|
||||
private:
|
||||
mspace _mspace;
|
||||
} s_videoRamPool, s_blitterPool;
|
||||
|
||||
static MemoryPool *s_currentPool;
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
void Surface::create(int16 width, int16 height, const PixelFormat &f) {
|
||||
assert(width >= 0 && height >= 0);
|
||||
free();
|
||||
|
||||
w = width;
|
||||
h = height;
|
||||
format = f;
|
||||
pitch = w * format.bytesPerPixel;
|
||||
|
||||
if (width && height) {
|
||||
if (s_currentPool) {
|
||||
pixels = s_currentPool->calloc(height * pitch, format.bytesPerPixel);
|
||||
if (!pixels)
|
||||
error("Not enough VRAM to allocate a surface");
|
||||
|
||||
if (s_currentPool == &s_blitterPool) {
|
||||
assert(pixels >= (void *)0xA1000000);
|
||||
} else if (s_currentPool == &s_videoRamPool) {
|
||||
#ifdef USE_SUPERVIDEL
|
||||
if (g_hasSuperVidel)
|
||||
assert(pixels >= (void *)0xA0000000 && pixels < (void *)0xA1000000);
|
||||
else
|
||||
#endif
|
||||
assert(pixels < (void *)0x01000000);
|
||||
}
|
||||
} else {
|
||||
pixels = ::calloc(height * pitch, format.bytesPerPixel);
|
||||
if (!pixels)
|
||||
error("Not enough RAM to allocate a surface");
|
||||
}
|
||||
|
||||
assert(((uintptr)pixels & (MALLOC_ALIGNMENT - 1)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::free() {
|
||||
if (pixels) {
|
||||
if (s_currentPool)
|
||||
s_currentPool->free(pixels);
|
||||
else
|
||||
::free(pixels);
|
||||
|
||||
pixels = nullptr;
|
||||
}
|
||||
|
||||
w = h = pitch = 0;
|
||||
format = PixelFormat();
|
||||
}
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AtariSurface::AtariSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat) {
|
||||
create(width, height, pixelFormat);
|
||||
}
|
||||
|
||||
AtariSurface::~AtariSurface() {
|
||||
free();
|
||||
}
|
||||
|
||||
void AtariSurface::create(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat) {
|
||||
MemoryPool *oldPool = s_currentPool;
|
||||
s_currentPool = &s_videoRamPool;
|
||||
|
||||
Graphics::ManagedSurface::create(width * (format == PIXELFORMAT_RGB121 ? 4 : 8) / 8, height, pixelFormat);
|
||||
w = width;
|
||||
|
||||
s_currentPool = oldPool;
|
||||
}
|
||||
|
||||
void AtariSurface::free() {
|
||||
MemoryPool *oldPool = s_currentPool;
|
||||
s_currentPool = &s_videoRamPool;
|
||||
|
||||
Graphics::ManagedSurface::free();
|
||||
|
||||
s_currentPool = oldPool;
|
||||
}
|
||||
|
||||
void AtariSurface::copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) {
|
||||
assert(width % 16 == 0);
|
||||
assert(destX % 16 == 0);
|
||||
assert(format.bytesPerPixel == 1);
|
||||
|
||||
const byte *pChunky = (const byte *)buffer;
|
||||
const byte *pChunkyEnd = pChunky + (height - 1) * srcPitch + width;
|
||||
|
||||
byte *pScreen = (byte *)getBasePtr(0, destY) + destX * getBitsPerPixel()/8;
|
||||
|
||||
if (getBitsPerPixel() == 8) {
|
||||
if (srcPitch == width) {
|
||||
if (srcPitch == pitch) {
|
||||
asm_c2p1x1_8(pChunky, pChunkyEnd, pScreen);
|
||||
return;
|
||||
} else if (srcPitch == pitch/2) {
|
||||
asm_c2p1x1_8_tt(pChunky, pChunkyEnd, pScreen, pitch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
asm_c2p1x1_8_rect(
|
||||
pChunky, pChunkyEnd,
|
||||
width,
|
||||
srcPitch,
|
||||
pScreen,
|
||||
pitch);
|
||||
} else {
|
||||
if (srcPitch == width && srcPitch/2 == pitch) {
|
||||
asm_c2p1x1_4(pChunky, pChunkyEnd, pScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
asm_c2p1x1_4_rect(
|
||||
pChunky, pChunkyEnd,
|
||||
width,
|
||||
srcPitch,
|
||||
pScreen,
|
||||
pitch);
|
||||
}
|
||||
}
|
||||
|
||||
void AtariSurface::drawMaskedSprite(
|
||||
const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
|
||||
const Graphics::Surface &boundingSurface,
|
||||
int destX, int destY,
|
||||
const Common::Rect &subRect) {
|
||||
assert(srcSurface.w == srcMask.w);
|
||||
assert(srcSurface.h == srcMask.h);
|
||||
|
||||
bool skipFirstPix16 = false;
|
||||
bool skipLastPix16 = false;
|
||||
|
||||
int srcSurfaceLeft = 0;
|
||||
int srcSurfaceWidth = srcSurface.w;
|
||||
int dstSurfaceLeft = 0;
|
||||
|
||||
if (subRect.left > 0) {
|
||||
skipFirstPix16 = true;
|
||||
|
||||
const int offset = subRect.left & (-16);
|
||||
srcSurfaceLeft += offset;
|
||||
srcSurfaceWidth -= offset;
|
||||
|
||||
destX = 16 - (subRect.left & (16-1));
|
||||
dstSurfaceLeft -= 16;
|
||||
}
|
||||
|
||||
if (destX + srcSurfaceWidth > boundingSurface.w) {
|
||||
skipLastPix16 = true;
|
||||
|
||||
const int offset = (destX + srcSurfaceWidth - boundingSurface.w) & (-16);
|
||||
srcSurfaceWidth -= offset;
|
||||
}
|
||||
|
||||
assert(srcSurfaceLeft % 16 == 0);
|
||||
assert(srcSurfaceWidth % 16 == 0);
|
||||
|
||||
destX += (this->w - boundingSurface.w) / 2;
|
||||
|
||||
if (getBitsPerPixel() == 8) {
|
||||
asm_draw_8bpl_sprite(
|
||||
(uint16 *)getBasePtr(dstSurfaceLeft, 0),
|
||||
(const uint16 *)srcSurface.getBasePtr(srcSurfaceLeft, subRect.top),
|
||||
(const uint16 *)srcMask.getBasePtr(srcSurfaceLeft / 8, subRect.top),
|
||||
destX, destY,
|
||||
pitch, srcSurface.w, srcSurfaceWidth, subRect.height(),
|
||||
skipFirstPix16, skipLastPix16);
|
||||
} else {
|
||||
asm_draw_4bpl_sprite(
|
||||
(uint16 *)getBasePtr(dstSurfaceLeft / 2, 0),
|
||||
(const uint16 *)srcSurface.getBasePtr(srcSurfaceLeft / 2, subRect.top),
|
||||
(const uint16 *)srcMask.getBasePtr(srcSurfaceLeft / 8, subRect.top),
|
||||
destX, destY,
|
||||
pitch, srcSurface.w / 2, srcSurfaceWidth, subRect.height(),
|
||||
skipFirstPix16, skipLastPix16);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef USE_SUPERVIDEL
|
||||
static long hasSvRamBoosted() {
|
||||
register long ret __asm__ ("d0") = 0;
|
||||
|
||||
__asm__ volatile(
|
||||
"\tmovec %%itt0,%%d1\n"
|
||||
"\tcmp.l #0xA007E060,%%d1\n"
|
||||
"\tbne.s 1f\n"
|
||||
|
||||
"\tmovec %%dtt0,%%d1\n"
|
||||
"\tcmp.l #0xA007E060,%%d1\n"
|
||||
"\tbne.s 1f\n"
|
||||
|
||||
"\tmoveq #1,%%d0\n"
|
||||
|
||||
"1:\n"
|
||||
: "=g"(ret) /* outputs */
|
||||
: /* inputs */
|
||||
: __CLOBBER_RETURN("d0") "d1", "cc"
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif // USE_SUPERVIDEL
|
||||
|
||||
void AtariSurfaceInit() {
|
||||
#ifdef USE_SUPERVIDEL
|
||||
g_hasSuperVidel = Getcookie(C_SupV, NULL) == C_FOUND && VgetMonitor() == MON_VGA;
|
||||
|
||||
if (g_hasSuperVidel) {
|
||||
#ifdef USE_SV_BLITTER
|
||||
g_superVidelFwVersion = *SV_VERSION & 0x01ff;
|
||||
|
||||
atari_debug("SuperVidel FW Revision: %d, using %s", g_superVidelFwVersion,
|
||||
g_superVidelFwVersion >= 9 ? "fast async FIFO" : "slower sync blitting");
|
||||
#else
|
||||
atari_debug("SuperVidel FW Revision: %d, SuperBlitter not used", *SV_VERSION & 0x01ff);
|
||||
#endif
|
||||
if (Supexec(hasSvRamBoosted))
|
||||
atari_debug("SV_XBIOS has the pmmu boost enabled");
|
||||
else
|
||||
atari_warning("SV_XBIOS has the pmmu boost disabled, set 'pmmu_boost = true' in C:\\SV.INF");
|
||||
|
||||
#ifdef USE_SV_BLITTER
|
||||
s_blitterPool.size = ct60_vmalloc(-1) - (16 * 1024 * 1024); // SV XBIOS seems to forget the initial 16 MB ST RAM mirror
|
||||
s_blitterPool.base = s_blitterPool.size > 0 ? ct60_vmalloc(s_blitterPool.size) : 0;
|
||||
s_blitterPool.create();
|
||||
// default pool is either null or blitter
|
||||
s_currentPool = &s_blitterPool;
|
||||
#endif
|
||||
}
|
||||
#endif // USE_SUPERVIDEL
|
||||
|
||||
s_videoRamPool.size = 2 * 1024 * 1024; // allocate 2 MiB, leave the rest for SDMA / Blitter usage
|
||||
s_videoRamPool.base = s_videoRamPool.size > 0 ? Mxalloc(s_videoRamPool.size, MX_STRAM) : 0;
|
||||
#ifdef USE_SUPERVIDEL
|
||||
if (g_hasSuperVidel && s_videoRamPool.base)
|
||||
s_videoRamPool.base |= 0xA0000000;
|
||||
#endif
|
||||
s_videoRamPool.create();
|
||||
}
|
||||
|
||||
void AtariSurfaceDeinit() {
|
||||
s_videoRamPool.destroy();
|
||||
if (s_videoRamPool.base) {
|
||||
#ifdef USE_SUPERVIDEL
|
||||
if (g_hasSuperVidel)
|
||||
s_videoRamPool.base &= 0x00FFFFFF;
|
||||
#endif
|
||||
Mfree(s_videoRamPool.base);
|
||||
s_videoRamPool.base = 0;
|
||||
s_videoRamPool.size = 0;
|
||||
}
|
||||
|
||||
#ifdef USE_SV_BLITTER
|
||||
s_blitterPool.destroy();
|
||||
if (s_blitterPool.base) {
|
||||
ct60_vmfree(s_blitterPool.base);
|
||||
s_blitterPool.base = 0;
|
||||
s_blitterPool.size = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
114
backends/graphics/atari/atari-surface.h
Normal file
114
backends/graphics/atari/atari-surface.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ATARI_SURFACE_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_SURFACE_H
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "backends/graphics/atari/atari-supervidel.h"
|
||||
|
||||
constexpr Graphics::PixelFormat PIXELFORMAT_CLUT8 = Graphics::PixelFormat::createFormatCLUT8();
|
||||
constexpr Graphics::PixelFormat PIXELFORMAT_RGB332 = Graphics::PixelFormat(1, 3, 3, 2, 0, 5, 2, 0, 0);
|
||||
constexpr Graphics::PixelFormat PIXELFORMAT_RGB121 = Graphics::PixelFormat(1, 1, 2, 1, 0, 3, 1, 0, 0);
|
||||
|
||||
class AtariSurface : public Graphics::ManagedSurface {
|
||||
public:
|
||||
AtariSurface() = default;
|
||||
AtariSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat);
|
||||
~AtariSurface() override;
|
||||
|
||||
using Graphics::ManagedSurface::create;
|
||||
void create(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat) final override;
|
||||
void free() final override;
|
||||
|
||||
void addDirtyRect(const Common::Rect &r) final override {};
|
||||
|
||||
// no override as ManagedSurface::copyRectToSurface is not a virtual function!
|
||||
virtual void copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height);
|
||||
virtual void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect &subRect) {
|
||||
assert(subRect.left % 16 == 0);
|
||||
assert(srcSurface.format == format);
|
||||
|
||||
copyRectToSurface(
|
||||
srcSurface.getBasePtr(subRect.left, subRect.top), srcSurface.pitch,
|
||||
destX, destY,
|
||||
subRect.width(), subRect.height());
|
||||
}
|
||||
|
||||
virtual void drawMaskedSprite(const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
|
||||
const Graphics::Surface &boundingSurface,
|
||||
int destX, int destY,
|
||||
const Common::Rect &subRect);
|
||||
|
||||
int getBitsPerPixel() const {
|
||||
return format == PIXELFORMAT_RGB121 ? 4 : 8;
|
||||
}
|
||||
|
||||
static Common::Rect alignRect(int x1, int y1, int x2, int y2) {
|
||||
// make non-virtual for performance reasons
|
||||
return g_hasSuperVidel
|
||||
? Common::Rect(x1, y1, x2, y2)
|
||||
: Common::Rect(x1 & (-16), y1, (x2 + 15) & (-16), y2);
|
||||
}
|
||||
static Common::Rect alignRect(const Common::Rect &rect) {
|
||||
// make non-virtual for performance reasons
|
||||
return g_hasSuperVidel
|
||||
? rect
|
||||
: Common::Rect(rect.left & (-16), rect.top, (rect.right + 15) & (-16), rect.bottom);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef USE_SUPERVIDEL
|
||||
class SuperVidelSurface final : public AtariSurface {
|
||||
public:
|
||||
SuperVidelSurface() = default;
|
||||
SuperVidelSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat)
|
||||
: AtariSurface(width, height, pixelFormat) {
|
||||
}
|
||||
|
||||
//using Graphics::ManagedSurface::copyRectToSurface;
|
||||
void copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) override {
|
||||
Graphics::ManagedSurface::copyRectToSurface(buffer, srcPitch, destX, destY, width, height);
|
||||
}
|
||||
void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect &subRect) override {
|
||||
Graphics::ManagedSurface::copyRectToSurface(srcSurface, destX, destY, subRect);
|
||||
}
|
||||
|
||||
void drawMaskedSprite(const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
|
||||
const Graphics::Surface &boundingSurface,
|
||||
int destX, int destY,
|
||||
const Common::Rect &subRect) override {
|
||||
#ifdef USE_SV_BLITTER
|
||||
g_blitMask = (const byte *)srcMask.getBasePtr(subRect.left, subRect.top);
|
||||
#endif
|
||||
copyRectToSurfaceWithKey(srcSurface, destX, destY, subRect, 0);
|
||||
#ifdef USE_SV_BLITTER
|
||||
g_blitMask = nullptr;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
void AtariSurfaceInit();
|
||||
void AtariSurfaceDeinit();
|
||||
|
||||
#endif // BACKENDS_GRAPHICS_ATARI_SURFACE_H
|
||||
59
backends/graphics/default-palette.h
Normal file
59
backends/graphics/default-palette.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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 BACKENDS_GRAPHICS_DEFAULT_PALETTE_H
|
||||
#define BACKENDS_GRAPHICS_DEFAULT_PALETTE_H
|
||||
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
/**
|
||||
* This is a default implementation of the PaletteManager interface
|
||||
* which ensures that grabPalette works as specified. Of course
|
||||
* it is still necessary to provide code that actually updates
|
||||
* the (possibly emulated) "hardware" palette of the backend.
|
||||
* For this purpose, implement the abstract setPaletteIntern
|
||||
* method.
|
||||
*/
|
||||
class DefaultPaletteManager : public PaletteManager {
|
||||
protected:
|
||||
byte _palette[3 * 256];
|
||||
|
||||
/**
|
||||
* Subclasses should only implement this method and none of the others.
|
||||
* Its semantics are like that of setPalette, only that it does not need
|
||||
* to worry about making it possible to query the palette values once they
|
||||
* have been set.
|
||||
*/
|
||||
virtual void setPaletteIntern(const byte *colors, uint start, uint num) = 0;
|
||||
|
||||
public:
|
||||
void setPalette(const byte *colors, uint start, uint num) {
|
||||
assert(start + num <= 256);
|
||||
memcpy(_palette + 3 * start, colors, 3 * num);
|
||||
setPaletteIntern(colors, start, num);
|
||||
}
|
||||
void grabPalette(byte *colors, uint start, uint num) const {
|
||||
assert(start + num <= 256);
|
||||
memcpy(colors, _palette + 3 * start, 3 * num);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
134
backends/graphics/graphics.h
Normal file
134
backends/graphics/graphics.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/* 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 BACKENDS_GRAPHICS_ABSTRACT_H
|
||||
#define BACKENDS_GRAPHICS_ABSTRACT_H
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/noncopyable.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/rotationmode.h"
|
||||
|
||||
#include "graphics/mode.h"
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
/**
|
||||
* Abstract class for graphics manager. Subclasses
|
||||
* implement the real functionality.
|
||||
*/
|
||||
class GraphicsManager : public PaletteManager {
|
||||
public:
|
||||
virtual ~GraphicsManager() {}
|
||||
|
||||
virtual bool hasFeature(OSystem::Feature f) const = 0;
|
||||
virtual void setFeatureState(OSystem::Feature f, bool enable) = 0;
|
||||
virtual bool getFeatureState(OSystem::Feature f) const = 0;
|
||||
|
||||
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const {
|
||||
static const OSystem::GraphicsMode noGraphicsModes[] = {{"NONE", "Normal", 0}, {nullptr, nullptr, 0 }};
|
||||
return noGraphicsModes;
|
||||
}
|
||||
virtual int getDefaultGraphicsMode() const { return 0; }
|
||||
virtual bool setGraphicsMode(int mode, uint flags = OSystem::kGfxModeNoFlags) { return (mode == 0); }
|
||||
virtual int getGraphicsMode() const { return 0; }
|
||||
#if defined(USE_IMGUI)
|
||||
virtual void setImGuiCallbacks(const ImGuiCallbacks &callbacks) { }
|
||||
virtual void *getImGuiTexture(const Graphics::Surface &image, const byte *palette, int palCount) { return nullptr; }
|
||||
virtual void freeImGuiTexture(void *texture) { }
|
||||
#endif
|
||||
virtual bool setShader(const Common::Path &fileName) { return false; }
|
||||
virtual const OSystem::GraphicsMode *getSupportedStretchModes() const {
|
||||
static const OSystem::GraphicsMode noStretchModes[] = {{"NONE", "Normal", 0}, {nullptr, nullptr, 0 }};
|
||||
return noStretchModes;
|
||||
}
|
||||
virtual int getDefaultStretchMode() const { return 0; }
|
||||
virtual bool setStretchMode(int mode) { return false; }
|
||||
virtual int getStretchMode() const { return 0; }
|
||||
virtual bool setRotationMode(Common::RotationMode rotation) { return false; }
|
||||
virtual uint getDefaultScaler() const { return 0; }
|
||||
virtual uint getDefaultScaleFactor() const { return 1; }
|
||||
virtual bool setScaler(uint mode, int factor) { return false; }
|
||||
virtual uint getScaler() const { return 0; }
|
||||
virtual uint getScaleFactor() const { return 1; }
|
||||
|
||||
#ifdef USE_RGB_COLOR
|
||||
virtual Graphics::PixelFormat getScreenFormat() const = 0;
|
||||
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const = 0;
|
||||
#endif
|
||||
virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) = 0;
|
||||
virtual void initSizeHint(const Graphics::ModeList &modes) {}
|
||||
virtual int getScreenChangeID() const = 0;
|
||||
|
||||
virtual void beginGFXTransaction() = 0;
|
||||
virtual OSystem::TransactionError endGFXTransaction() = 0;
|
||||
|
||||
virtual int16 getHeight() const = 0;
|
||||
virtual int16 getWidth() const = 0;
|
||||
virtual void setPalette(const byte *colors, uint start, uint num) = 0;
|
||||
virtual void grabPalette(byte *colors, uint start, uint num) const = 0;
|
||||
virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) = 0;
|
||||
virtual Graphics::Surface *lockScreen() = 0;
|
||||
virtual void unlockScreen() = 0;
|
||||
virtual void fillScreen(uint32 col) = 0;
|
||||
virtual void fillScreen(const Common::Rect &r, uint32 col) = 0;
|
||||
virtual void updateScreen() = 0;
|
||||
virtual void presentBuffer() {}
|
||||
virtual void setShakePos(int shakeXOffset, int shakeYOffset) = 0;
|
||||
virtual void setFocusRectangle(const Common::Rect& rect) = 0;
|
||||
virtual void clearFocusRectangle() = 0;
|
||||
|
||||
virtual void showOverlay(bool inGUI) = 0;
|
||||
virtual void hideOverlay() = 0;
|
||||
virtual bool isOverlayVisible() const = 0;
|
||||
virtual Graphics::PixelFormat getOverlayFormat() const = 0;
|
||||
virtual void clearOverlay() = 0;
|
||||
virtual void grabOverlay(Graphics::Surface &surface) const = 0;
|
||||
virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) = 0;
|
||||
virtual int16 getOverlayHeight() const = 0;
|
||||
virtual int16 getOverlayWidth() const = 0;
|
||||
virtual Common::Rect getSafeOverlayArea(int16 *width, int16 *height) const {
|
||||
int16 w = getOverlayWidth(),
|
||||
h = getOverlayHeight();
|
||||
if (width) *width = w;
|
||||
if (height) *height = h;
|
||||
return Common::Rect(w, h);
|
||||
}
|
||||
virtual float getHiDPIScreenFactor() const { return 1.0f; }
|
||||
|
||||
virtual bool showMouse(bool visible) = 0;
|
||||
virtual void warpMouse(int x, int y) = 0;
|
||||
virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = nullptr, const byte *mask = nullptr) = 0;
|
||||
virtual void setCursorPalette(const byte *colors, uint start, uint num) = 0;
|
||||
|
||||
virtual void displayMessageOnOSD(const Common::U32String &msg) {}
|
||||
virtual void displayActivityIconOnOSD(const Graphics::Surface *icon) {}
|
||||
|
||||
|
||||
// Graphics::PaletteManager interface
|
||||
//virtual void setPalette(const byte *colors, uint start, uint num) = 0;
|
||||
//virtual void grabPalette(byte *colors, uint start, uint num) const = 0;
|
||||
|
||||
virtual void saveScreenshot() {}
|
||||
virtual bool lockMouse(bool lock) { return false; }
|
||||
};
|
||||
|
||||
#endif
|
||||
117
backends/graphics/ios/ios-graphics.cpp
Normal file
117
backends/graphics/ios/ios-graphics.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/graphics/ios/ios-graphics.h"
|
||||
#include "backends/graphics/ios/renderbuffer.h"
|
||||
#include "backends/graphics/opengl/pipelines/pipeline.h"
|
||||
#include "backends/platform/ios7/ios7_osys_main.h"
|
||||
|
||||
iOSGraphicsManager::iOSGraphicsManager() :
|
||||
_insets{0, 0, 0, 0} {
|
||||
initSurface();
|
||||
}
|
||||
|
||||
iOSGraphicsManager::~iOSGraphicsManager() {
|
||||
deinitSurface();
|
||||
}
|
||||
|
||||
void iOSGraphicsManager::initSurface() {
|
||||
OSystem_iOS7 *sys = dynamic_cast<OSystem_iOS7 *>(g_system);
|
||||
|
||||
// Create OpenGL context
|
||||
GLuint rbo = sys->createOpenGLContext();
|
||||
|
||||
notifyContextCreate(OpenGL::kContextGLES2,
|
||||
new OpenGL::RenderbufferTarget(rbo),
|
||||
OpenGL::Texture::getRGBAPixelFormat(),
|
||||
OpenGL::Texture::getRGBAPixelFormat());
|
||||
handleResize(sys->getScreenWidth(), sys->getScreenHeight());
|
||||
|
||||
_old_touch_mode = kTouchModeTouchpad;
|
||||
|
||||
// not in 3D, not in GUI
|
||||
sys->applyTouchSettings(false, false);
|
||||
}
|
||||
|
||||
void iOSGraphicsManager::deinitSurface() {
|
||||
notifyContextDestroy();
|
||||
dynamic_cast<OSystem_iOS7 *>(g_system)->destroyOpenGLContext();
|
||||
}
|
||||
|
||||
void iOSGraphicsManager::notifyResize(const int width, const int height) {
|
||||
handleResize(width, height);
|
||||
}
|
||||
|
||||
bool iOSGraphicsManager::loadVideoMode(uint requestedWidth, uint requestedHeight, bool resizable, int antialiasing) {
|
||||
// As GLES2 provides FBO, OpenGL graphics manager must ask us for a resizable surface
|
||||
assert(resizable);
|
||||
if (antialiasing != 0) {
|
||||
warning("Requesting antialiased video mode while not available");
|
||||
}
|
||||
|
||||
/* The iOS and tvOS video modes are always full screen */
|
||||
return true;
|
||||
}
|
||||
|
||||
void iOSGraphicsManager::showOverlay(bool inGUI) {
|
||||
if (_overlayVisible && inGUI == _overlayInGUI)
|
||||
return;
|
||||
|
||||
// Don't change touch mode when not changing mouse coordinates
|
||||
if (inGUI) {
|
||||
_old_touch_mode = dynamic_cast<OSystem_iOS7 *>(g_system)->getCurrentTouchMode();
|
||||
// not in 3D, in overlay
|
||||
dynamic_cast<OSystem_iOS7 *>(g_system)->applyTouchSettings(false, true);
|
||||
} else if (_overlayInGUI) {
|
||||
// Restore touch mode active before overlay was shown
|
||||
dynamic_cast<OSystem_iOS7 *>(g_system)->setCurrentTouchMode(static_cast<TouchMode>(_old_touch_mode));
|
||||
}
|
||||
|
||||
OpenGL::OpenGLGraphicsManager::showOverlay(inGUI);
|
||||
}
|
||||
|
||||
void iOSGraphicsManager::hideOverlay() {
|
||||
if (_overlayInGUI) {
|
||||
// Restore touch mode active before overlay was shown
|
||||
dynamic_cast<OSystem_iOS7 *>(g_system)->setCurrentTouchMode(static_cast<TouchMode>(_old_touch_mode));
|
||||
}
|
||||
|
||||
OpenGL::OpenGLGraphicsManager::hideOverlay();
|
||||
}
|
||||
|
||||
float iOSGraphicsManager::getHiDPIScreenFactor() const {
|
||||
return dynamic_cast<OSystem_iOS7 *>(g_system)->getSystemHiDPIScreenFactor();
|
||||
}
|
||||
|
||||
void iOSGraphicsManager::refreshScreen() {
|
||||
dynamic_cast<OSystem_iOS7 *>(g_system)->refreshScreen();
|
||||
}
|
||||
|
||||
bool iOSGraphicsManager::notifyMousePosition(Common::Point &mouse) {
|
||||
mouse.x = CLIP<int16>(mouse.x, _activeArea.drawRect.left, _activeArea.drawRect.right);
|
||||
mouse.y = CLIP<int16>(mouse.y, _activeArea.drawRect.top, _activeArea.drawRect.bottom);
|
||||
|
||||
setMousePosition(mouse.x, mouse.y);
|
||||
mouse = convertWindowToVirtual(mouse.x, mouse.y);
|
||||
|
||||
return true;
|
||||
}
|
||||
62
backends/graphics/ios/ios-graphics.h
Normal file
62
backends/graphics/ios/ios-graphics.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* 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 BACKENDS_GRAPHICS_IOS_IOS_GRAPHICS_H
|
||||
#define BACKENDS_GRAPHICS_IOS_IOS_GRAPHICS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
|
||||
#include "backends/graphics/opengl/opengl-graphics.h"
|
||||
|
||||
class iOSGraphicsManager :
|
||||
public OpenGL::OpenGLGraphicsManager {
|
||||
public:
|
||||
iOSGraphicsManager();
|
||||
virtual ~iOSGraphicsManager();
|
||||
|
||||
void initSurface();
|
||||
void deinitSurface();
|
||||
|
||||
void notifyResize(const int width, const int height);
|
||||
|
||||
bool notifyMousePosition(Common::Point &mouse);
|
||||
Common::Point getMousePosition() { return Common::Point(_cursorX, _cursorY); }
|
||||
|
||||
float getHiDPIScreenFactor() const override;
|
||||
|
||||
void setSafeAreaInsets(int l, int r, int t, int b) { _insets.left = l; _insets.top = t; _insets.right = r; _insets.bottom = b; }
|
||||
WindowedGraphicsManager::Insets getSafeAreaInsets() const override { return _insets; }
|
||||
|
||||
protected:
|
||||
void setSystemMousePosition(const int x, const int y) override {}
|
||||
|
||||
bool loadVideoMode(uint requestedWidth, uint requestedHeight, bool resizable, int antialiasing) override;
|
||||
void showOverlay(bool inGUI) override;
|
||||
void hideOverlay() override;
|
||||
|
||||
void refreshScreen() override;
|
||||
|
||||
int _old_touch_mode;
|
||||
WindowedGraphicsManager::Insets _insets;
|
||||
};
|
||||
|
||||
#endif
|
||||
92
backends/graphics/ios/renderbuffer.cpp
Normal file
92
backends/graphics/ios/renderbuffer.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/* 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 "backends/graphics/ios/renderbuffer.h"
|
||||
#include "graphics/opengl/debug.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
//
|
||||
// Render to backbuffer target implementation
|
||||
//
|
||||
RenderbufferTarget::RenderbufferTarget(GLuint renderbufferID)
|
||||
: _glRBO(renderbufferID), _glFBO(0) {
|
||||
}
|
||||
|
||||
RenderbufferTarget::~RenderbufferTarget() {
|
||||
GL_CALL_SAFE(glDeleteFramebuffers, (1, &_glFBO));
|
||||
}
|
||||
|
||||
void RenderbufferTarget::activateInternal() {
|
||||
bool needUpdate = false;
|
||||
|
||||
// Allocate framebuffer object if necessary.
|
||||
if (!_glFBO) {
|
||||
GL_CALL(glGenFramebuffers(1, &_glFBO));
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
// Attach FBO to rendering context.
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, _glFBO));
|
||||
|
||||
// Attach render buffer to newly created FBO.
|
||||
if (needUpdate) {
|
||||
GL_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _glRBO));
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderbufferTarget::setSize(uint width, uint height) {
|
||||
// Set viewport dimensions.
|
||||
_viewport[0] = 0;
|
||||
_viewport[1] = 0;
|
||||
_viewport[2] = width;
|
||||
_viewport[3] = height;
|
||||
|
||||
// Setup orthogonal projection matrix.
|
||||
_projectionMatrix(0, 0) = 2.0f / width;
|
||||
_projectionMatrix(0, 1) = 0.0f;
|
||||
_projectionMatrix(0, 2) = 0.0f;
|
||||
_projectionMatrix(0, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(1, 0) = 0.0f;
|
||||
_projectionMatrix(1, 1) = -2.0f / height;
|
||||
_projectionMatrix(1, 2) = 0.0f;
|
||||
_projectionMatrix(1, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(2, 0) = 0.0f;
|
||||
_projectionMatrix(2, 1) = 0.0f;
|
||||
_projectionMatrix(2, 2) = 0.0f;
|
||||
_projectionMatrix(2, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(3, 0) = -1.0f;
|
||||
_projectionMatrix(3, 1) = 1.0f;
|
||||
_projectionMatrix(3, 2) = 0.0f;
|
||||
_projectionMatrix(3, 3) = 1.0f;
|
||||
|
||||
// Directly apply changes when we are active.
|
||||
if (isActive()) {
|
||||
applyViewport();
|
||||
applyProjectionMatrix();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace OpenGL
|
||||
55
backends/graphics/ios/renderbuffer.h
Normal file
55
backends/graphics/ios/renderbuffer.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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 BACKENDS_GRAPHICS_IOS_RENDERBUFFER_H
|
||||
#define BACKENDS_GRAPHICS_IOS_RENDERBUFFER_H
|
||||
|
||||
#include "backends/graphics/opengl/framebuffer.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
/**
|
||||
* Render to renderbuffer framebuffer implementation.
|
||||
*
|
||||
* This target allows to render to a renderbuffer, which can then be used as
|
||||
* a rendering source like expected on iOS.
|
||||
*/
|
||||
class RenderbufferTarget : public Framebuffer {
|
||||
public:
|
||||
RenderbufferTarget(GLuint renderbufferID);
|
||||
~RenderbufferTarget() override;
|
||||
|
||||
/**
|
||||
* Set size of the render target.
|
||||
*/
|
||||
bool setSize(uint width, uint height) override;
|
||||
|
||||
protected:
|
||||
void activateInternal() override;
|
||||
|
||||
private:
|
||||
GLuint _glRBO;
|
||||
GLuint _glFBO;
|
||||
};
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
55
backends/graphics/maemosdl/maemosdl-graphics.cpp
Normal file
55
backends/graphics/maemosdl/maemosdl-graphics.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
#if defined(MAEMO)
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "backends/platform/maemo/maemo.h"
|
||||
#include "backends/graphics/maemosdl/maemosdl-graphics.h"
|
||||
|
||||
MaemoSdlGraphicsManager::MaemoSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window)
|
||||
: SurfaceSdlGraphicsManager(sdlEventSource, window) {
|
||||
}
|
||||
|
||||
bool MaemoSdlGraphicsManager::loadGFXMode() {
|
||||
bool success = SurfaceSdlGraphicsManager::loadGFXMode();
|
||||
|
||||
// fix the problematic zoom key capture in Maemo5/N900
|
||||
SDL_SysWMinfo info;
|
||||
if (_window->getSDLWMInformation(&info)) {
|
||||
Display *dpy = info.info.x11.display;
|
||||
Window win;
|
||||
unsigned long val = 1;
|
||||
Atom atom_zoom = XInternAtom(dpy, "_HILDON_ZOOM_KEY_ATOM", 0);
|
||||
info.info.x11.lock_func();
|
||||
win = info.info.x11.fswindow;
|
||||
if (win)
|
||||
XChangeProperty(dpy, win, atom_zoom, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &val, 1); // grab zoom keys
|
||||
win = info.info.x11.wmwindow;
|
||||
if (win)
|
||||
XChangeProperty(dpy, win, atom_zoom, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &val, 1); // grab zoom keys
|
||||
info.info.x11.unlock_func();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
39
backends/graphics/maemosdl/maemosdl-graphics.h
Normal file
39
backends/graphics/maemosdl/maemosdl-graphics.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(MAEMO)
|
||||
|
||||
#ifndef BACKENDS_GRAPHICS_MAEMOSDL_GRAPHICS_H
|
||||
#define BACKENDS_GRAPHICS_MAEMOSDL_GRAPHICS_H
|
||||
|
||||
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
|
||||
|
||||
class MaemoSdlGraphicsManager final : public SurfaceSdlGraphicsManager {
|
||||
public:
|
||||
MaemoSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window);
|
||||
|
||||
protected:
|
||||
bool loadGFXMode() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
56
backends/graphics/miyoo/miyoomini-graphics.cpp
Normal file
56
backends/graphics/miyoo/miyoomini-graphics.cpp
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "backends/graphics/miyoo/miyoomini-graphics.h"
|
||||
|
||||
void MiyooMiniGraphicsManager::initGraphicsSurface() {
|
||||
_hwScreen = nullptr;
|
||||
_realHwScreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 32,
|
||||
SDL_HWSURFACE);
|
||||
if (!_realHwScreen)
|
||||
return;
|
||||
_hwScreen = SDL_CreateRGBSurface(SDL_HWSURFACE, _videoMode.hardwareWidth, _videoMode.hardwareHeight,
|
||||
_realHwScreen->format->BitsPerPixel,
|
||||
_realHwScreen->format->Rmask,
|
||||
_realHwScreen->format->Gmask,
|
||||
_realHwScreen->format->Bmask,
|
||||
_realHwScreen->format->Amask);
|
||||
_isDoubleBuf = false;
|
||||
_isHwPalette = false;
|
||||
}
|
||||
|
||||
void MiyooMiniGraphicsManager::unloadGFXMode() {
|
||||
if (_realHwScreen) {
|
||||
SDL_FreeSurface(_realHwScreen);
|
||||
_realHwScreen = nullptr;
|
||||
}
|
||||
SurfaceSdlGraphicsManager::unloadGFXMode();
|
||||
}
|
||||
|
||||
void MiyooMiniGraphicsManager::updateScreen(SDL_Rect *dirtyRectList, int actualDirtyRects) {
|
||||
SDL_BlitSurface(_hwScreen, nullptr, _realHwScreen, nullptr);
|
||||
SDL_UpdateRects(_realHwScreen, actualDirtyRects, _dirtyRectList);
|
||||
}
|
||||
|
||||
void MiyooMiniGraphicsManager::getDefaultResolution(uint &w, uint &h) {
|
||||
w = 640;
|
||||
h = 480;
|
||||
}
|
||||
40
backends/graphics/miyoo/miyoomini-graphics.h
Normal file
40
backends/graphics/miyoo/miyoomini-graphics.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* 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 BACKENDS_GRAPHICS_MIYOOMINI_H
|
||||
#define BACKENDS_GRAPHICS_MIYOOMINI_H
|
||||
|
||||
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
|
||||
|
||||
class MiyooMiniGraphicsManager : public SurfaceSdlGraphicsManager {
|
||||
public:
|
||||
MiyooMiniGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window) : SurfaceSdlGraphicsManager(sdlEventSource, window), _realHwScreen(nullptr) {}
|
||||
|
||||
void initGraphicsSurface() override;
|
||||
void unloadGFXMode() override;
|
||||
void updateScreen(SDL_Rect *dirtyRectList, int actualDirtyRects) override;
|
||||
void getDefaultResolution(uint &w, uint &h) override;
|
||||
|
||||
private:
|
||||
SDL_Surface *_realHwScreen;
|
||||
};
|
||||
|
||||
#endif /* BACKENDS_GRAPHICS_MIYOOMINI_H */
|
||||
98
backends/graphics/null/null-graphics.h
Normal file
98
backends/graphics/null/null-graphics.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/* 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 BACKENDS_GRAPHICS_NULL_H
|
||||
#define BACKENDS_GRAPHICS_NULL_H
|
||||
|
||||
#include "backends/graphics/graphics.h"
|
||||
|
||||
class NullGraphicsManager : public GraphicsManager {
|
||||
public:
|
||||
virtual ~NullGraphicsManager() {}
|
||||
|
||||
bool hasFeature(OSystem::Feature f) const override { return false; }
|
||||
void setFeatureState(OSystem::Feature f, bool enable) override {}
|
||||
bool getFeatureState(OSystem::Feature f) const override { return false; }
|
||||
|
||||
#ifdef USE_RGB_COLOR
|
||||
Graphics::PixelFormat getScreenFormat() const override {
|
||||
return _format;
|
||||
}
|
||||
|
||||
Common::List<Graphics::PixelFormat> getSupportedFormats() const override {
|
||||
Common::List<Graphics::PixelFormat> list;
|
||||
list.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); // BBDoU, Frotz, HDB, Hopkins, Nuvie, Petka, Riven, Sherlock (3DO), Titanic, Tony, Ultima 4, Ultima 8, ZVision
|
||||
list.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); // Full Pipe, Gnap (little endian), Griffon, Groovie 2, SCI32 (HQ videos), Sludge, Sword25, Ultima 8, Wintermute
|
||||
list.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)); // Gnap (big endian)
|
||||
list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); // SCUMM HE99+, Last Express
|
||||
list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15)); // Dragons
|
||||
list.push_back(Graphics::PixelFormat::createFormatCLUT8());
|
||||
return list;
|
||||
}
|
||||
#endif
|
||||
|
||||
void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) override {
|
||||
_width = width;
|
||||
_height = height;
|
||||
_format = format ? *format : Graphics::PixelFormat::createFormatCLUT8();
|
||||
}
|
||||
|
||||
int getScreenChangeID() const override { return 0; }
|
||||
|
||||
void beginGFXTransaction() override {}
|
||||
OSystem::TransactionError endGFXTransaction() override { return OSystem::kTransactionSuccess; }
|
||||
|
||||
int16 getHeight() const override { return _height; }
|
||||
int16 getWidth() const override { return _width; }
|
||||
void setPalette(const byte *colors, uint start, uint num) override {}
|
||||
void grabPalette(byte *colors, uint start, uint num) const override {}
|
||||
void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override {}
|
||||
Graphics::Surface *lockScreen() override { return NULL; }
|
||||
void unlockScreen() override {}
|
||||
void fillScreen(uint32 col) override {}
|
||||
void fillScreen(const Common::Rect &r, uint32 col) override {}
|
||||
void updateScreen() override {}
|
||||
void setShakePos(int shakeXOffset, int shakeYOffset) override {}
|
||||
void setFocusRectangle(const Common::Rect& rect) override {}
|
||||
void clearFocusRectangle() override {}
|
||||
|
||||
void showOverlay(bool inGUI) override { _overlayVisible = true; }
|
||||
void hideOverlay() override { _overlayVisible = false; }
|
||||
bool isOverlayVisible() const override { return _overlayVisible; }
|
||||
Graphics::PixelFormat getOverlayFormat() const override { return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); }
|
||||
void clearOverlay() override {}
|
||||
void grabOverlay(Graphics::Surface &surface) const override {}
|
||||
void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override {}
|
||||
int16 getOverlayHeight() const override { return _height; }
|
||||
int16 getOverlayWidth() const override { return _width; }
|
||||
|
||||
bool showMouse(bool visible) override { return !visible; }
|
||||
void warpMouse(int x, int y) override {}
|
||||
void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override {}
|
||||
void setCursorPalette(const byte *colors, uint start, uint num) override {}
|
||||
|
||||
private:
|
||||
uint _width, _height;
|
||||
Graphics::PixelFormat _format;
|
||||
bool _overlayVisible;
|
||||
};
|
||||
|
||||
#endif
|
||||
63
backends/graphics/opendingux/opendingux-graphics.cpp
Normal file
63
backends/graphics/opendingux/opendingux-graphics.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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 "backends/graphics/opendingux/opendingux-graphics.h"
|
||||
|
||||
void OpenDinguxGraphicsManager::initGraphicsSurface() {
|
||||
#ifdef RS90
|
||||
Uint32 flags = SDL_HWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
|
||||
int bpp = 8;
|
||||
#else
|
||||
Uint32 flags = SDL_SWSURFACE | SDL_FULLSCREEN;
|
||||
int bpp = 16;
|
||||
#endif
|
||||
_hwScreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, bpp, flags);
|
||||
_isDoubleBuf = flags & SDL_DOUBLEBUF;
|
||||
_isHwPalette = flags & SDL_HWPALETTE;
|
||||
}
|
||||
|
||||
void OpenDinguxGraphicsManager::getDefaultResolution(uint &w, uint &h) {
|
||||
#ifdef RS90
|
||||
SDL_PixelFormat p;
|
||||
p.BitsPerPixel = 16;
|
||||
p.BytesPerPixel = 2;
|
||||
p.Rloss = 3;
|
||||
p.Gloss = 2;
|
||||
p.Bloss = 3;
|
||||
p.Rshift = 11;
|
||||
p.Gshift = 5;
|
||||
p.Bshift = 0;
|
||||
p.Rmask = 0xf800;
|
||||
p.Gmask = 0x07e0;
|
||||
p.Bmask = 0x001f;
|
||||
p.colorkey = 0;
|
||||
p.alpha = 0;
|
||||
// Only native screen resolution is supported in RGB565 fullscreen hwsurface.
|
||||
SDL_Rect const* const*availableModes = SDL_ListModes(&p, SDL_FULLSCREEN|SDL_HWSURFACE);
|
||||
w = availableModes[0]->w;
|
||||
h = availableModes[0]->h;
|
||||
// Request 320x200 for the RG99, to let the software aspect correction kick in
|
||||
if ( w == 320 && h == 480 ) h = 200;
|
||||
#else
|
||||
w = 320;
|
||||
h = 200;
|
||||
#endif
|
||||
}
|
||||
35
backends/graphics/opendingux/opendingux-graphics.h
Normal file
35
backends/graphics/opendingux/opendingux-graphics.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENDINGUX_H
|
||||
#define BACKENDS_GRAPHICS_OPENDINGUX_H
|
||||
|
||||
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
|
||||
|
||||
class OpenDinguxGraphicsManager : public SurfaceSdlGraphicsManager {
|
||||
public:
|
||||
OpenDinguxGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window) : SurfaceSdlGraphicsManager(sdlEventSource, window) {}
|
||||
|
||||
void initGraphicsSurface() override;
|
||||
void getDefaultResolution(uint &w, uint &h) override;
|
||||
};
|
||||
|
||||
#endif /* BACKENDS_GRAPHICS_OPENDINGUX_H */
|
||||
316
backends/graphics/opengl/framebuffer.cpp
Normal file
316
backends/graphics/opengl/framebuffer.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/* 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 "backends/graphics/opengl/framebuffer.h"
|
||||
#include "backends/graphics/opengl/pipelines/pipeline.h"
|
||||
#include "graphics/opengl/debug.h"
|
||||
#include "graphics/opengl/texture.h"
|
||||
#include "common/rotationmode.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
Framebuffer::Framebuffer()
|
||||
: _viewport(), _projectionMatrix(), _pipeline(nullptr), _clearColor(),
|
||||
_blendState(kBlendModeDisabled), _scissorTestState(false), _scissorBox() {
|
||||
}
|
||||
|
||||
void Framebuffer::activate(Pipeline *pipeline) {
|
||||
assert(pipeline);
|
||||
_pipeline = pipeline;
|
||||
|
||||
applyViewport();
|
||||
applyProjectionMatrix();
|
||||
applyClearColor();
|
||||
applyBlendState();
|
||||
applyScissorTestState();
|
||||
applyScissorBox();
|
||||
|
||||
activateInternal();
|
||||
}
|
||||
|
||||
void Framebuffer::deactivate() {
|
||||
deactivateInternal();
|
||||
|
||||
_pipeline = nullptr;
|
||||
}
|
||||
|
||||
void Framebuffer::setClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
|
||||
_clearColor[0] = r;
|
||||
_clearColor[1] = g;
|
||||
_clearColor[2] = b;
|
||||
_clearColor[3] = a;
|
||||
|
||||
// Directly apply changes when we are active.
|
||||
if (isActive()) {
|
||||
applyClearColor();
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::enableBlend(BlendMode mode) {
|
||||
_blendState = mode;
|
||||
|
||||
// Directly apply changes when we are active.
|
||||
if (isActive()) {
|
||||
applyBlendState();
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::enableScissorTest(bool enable) {
|
||||
_scissorTestState = enable;
|
||||
|
||||
// Directly apply changes when we are active.
|
||||
if (isActive()) {
|
||||
applyScissorTestState();
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::setScissorBox(GLint x, GLint y, GLsizei w, GLsizei h) {
|
||||
_scissorBox[0] = x;
|
||||
_scissorBox[1] = y;
|
||||
_scissorBox[2] = w;
|
||||
_scissorBox[3] = h;
|
||||
|
||||
// Directly apply changes when we are active.
|
||||
if (isActive()) {
|
||||
applyScissorBox();
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::applyViewport() {
|
||||
GL_CALL(glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]));
|
||||
}
|
||||
|
||||
void Framebuffer::applyProjectionMatrix() {
|
||||
assert(_pipeline);
|
||||
_pipeline->setProjectionMatrix(_projectionMatrix);
|
||||
}
|
||||
|
||||
void Framebuffer::applyClearColor() {
|
||||
GL_CALL(glClearColor(_clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]));
|
||||
}
|
||||
|
||||
void Framebuffer::applyBlendState() {
|
||||
switch (_blendState) {
|
||||
case kBlendModeDisabled:
|
||||
GL_CALL(glDisable(GL_BLEND));
|
||||
break;
|
||||
case kBlendModeOpaque:
|
||||
if (!glBlendColor) {
|
||||
// If glBlendColor is not available (old OpenGL) fallback on disabling blending
|
||||
GL_CALL(glDisable(GL_BLEND));
|
||||
break;
|
||||
}
|
||||
GL_CALL(glEnable(GL_BLEND));
|
||||
GL_CALL(glBlendColor(1.f, 1.f, 1.f, 0.f));
|
||||
GL_CALL(glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR));
|
||||
break;
|
||||
case kBlendModeTraditionalTransparency:
|
||||
GL_CALL(glEnable(GL_BLEND));
|
||||
GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
break;
|
||||
case kBlendModePremultipliedTransparency:
|
||||
GL_CALL(glEnable(GL_BLEND));
|
||||
GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
|
||||
break;
|
||||
case kBlendModeAdditive:
|
||||
GL_CALL(glEnable(GL_BLEND));
|
||||
GL_CALL(glBlendFunc(GL_ONE, GL_ONE));
|
||||
break;
|
||||
case kBlendModeMaskAlphaAndInvertByColor:
|
||||
GL_CALL(glEnable(GL_BLEND));
|
||||
GL_CALL(glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::applyScissorTestState() {
|
||||
if (_scissorTestState) {
|
||||
GL_CALL(glEnable(GL_SCISSOR_TEST));
|
||||
} else {
|
||||
GL_CALL(glDisable(GL_SCISSOR_TEST));
|
||||
}
|
||||
}
|
||||
|
||||
void Framebuffer::applyScissorBox() {
|
||||
GL_CALL(glScissor(_scissorBox[0], _scissorBox[1], _scissorBox[2], _scissorBox[3]));
|
||||
}
|
||||
|
||||
void Framebuffer::copyRenderStateFrom(const Framebuffer &other, uint copyMask) {
|
||||
if (copyMask & kCopyMaskClearColor) {
|
||||
memcpy(_clearColor, other._clearColor, sizeof(_clearColor));
|
||||
}
|
||||
if (copyMask & kCopyMaskBlendState) {
|
||||
_blendState = other._blendState;
|
||||
}
|
||||
if (copyMask & kCopyMaskScissorState) {
|
||||
_scissorTestState = other._scissorTestState;
|
||||
}
|
||||
if (copyMask & kCopyMaskScissorBox) {
|
||||
memcpy(_scissorBox, other._scissorBox, sizeof(_scissorBox));
|
||||
}
|
||||
|
||||
if (isActive()) {
|
||||
applyClearColor();
|
||||
applyBlendState();
|
||||
applyScissorTestState();
|
||||
applyScissorBox();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Backbuffer implementation
|
||||
//
|
||||
|
||||
void Backbuffer::activateInternal() {
|
||||
#if !USE_FORCED_GLES
|
||||
if (OpenGLContext.framebufferObjectSupported) {
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Backbuffer::setSize(uint width, uint height) {
|
||||
// Set viewport dimensions.
|
||||
_viewport[0] = 0;
|
||||
_viewport[1] = 0;
|
||||
_viewport[2] = width;
|
||||
_viewport[3] = height;
|
||||
|
||||
// Setup orthogonal projection matrix.
|
||||
_projectionMatrix(0, 0) = 2.0f / width;
|
||||
_projectionMatrix(0, 1) = 0.0f;
|
||||
_projectionMatrix(0, 2) = 0.0f;
|
||||
_projectionMatrix(0, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(1, 0) = 0.0f;
|
||||
_projectionMatrix(1, 1) = -2.0f / height;
|
||||
_projectionMatrix(1, 2) = 0.0f;
|
||||
_projectionMatrix(1, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(2, 0) = 0.0f;
|
||||
_projectionMatrix(2, 1) = 0.0f;
|
||||
_projectionMatrix(2, 2) = 0.0f;
|
||||
_projectionMatrix(2, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(3, 0) = -1.0f;
|
||||
_projectionMatrix(3, 1) = 1.0f;
|
||||
_projectionMatrix(3, 2) = 0.0f;
|
||||
_projectionMatrix(3, 3) = 1.0f;
|
||||
|
||||
// Directly apply changes when we are active.
|
||||
if (isActive()) {
|
||||
applyViewport();
|
||||
applyProjectionMatrix();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Render to texture target implementation
|
||||
//
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
TextureTarget::TextureTarget()
|
||||
: _texture(new Texture(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE)), _glFBO(0), _needUpdate(true) {
|
||||
}
|
||||
|
||||
TextureTarget::~TextureTarget() {
|
||||
delete _texture;
|
||||
GL_CALL_SAFE(glDeleteFramebuffers, (1, &_glFBO));
|
||||
}
|
||||
|
||||
void TextureTarget::activateInternal() {
|
||||
// Allocate framebuffer object if necessary.
|
||||
if (!_glFBO) {
|
||||
GL_CALL(glGenFramebuffers(1, &_glFBO));
|
||||
_needUpdate = true;
|
||||
}
|
||||
|
||||
// Attach destination texture to FBO.
|
||||
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, _glFBO));
|
||||
|
||||
// If required attach texture to FBO.
|
||||
if (_needUpdate) {
|
||||
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture->getGLTexture(), 0));
|
||||
_needUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureTarget::destroy() {
|
||||
GL_CALL(glDeleteFramebuffers(1, &_glFBO));
|
||||
_glFBO = 0;
|
||||
|
||||
_texture->destroy();
|
||||
}
|
||||
|
||||
void TextureTarget::create() {
|
||||
_texture->create();
|
||||
|
||||
_needUpdate = true;
|
||||
}
|
||||
|
||||
bool TextureTarget::setSize(uint width, uint height) {
|
||||
if (!_texture->setSize(width, height)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint texWidth = _texture->getWidth();
|
||||
const uint texHeight = _texture->getHeight();
|
||||
|
||||
// Set viewport dimensions.
|
||||
_viewport[0] = 0;
|
||||
_viewport[1] = 0;
|
||||
_viewport[2] = texWidth;
|
||||
_viewport[3] = texHeight;
|
||||
|
||||
// Setup orthogonal projection matrix.
|
||||
_projectionMatrix(0, 0) = 2.0f / texWidth;
|
||||
_projectionMatrix(0, 1) = 0.0f;
|
||||
_projectionMatrix(0, 2) = 0.0f;
|
||||
_projectionMatrix(0, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(1, 0) = 0.0f;
|
||||
_projectionMatrix(1, 1) = 2.0f / texHeight;
|
||||
_projectionMatrix(1, 2) = 0.0f;
|
||||
_projectionMatrix(1, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(2, 0) = 0.0f;
|
||||
_projectionMatrix(2, 1) = 0.0f;
|
||||
_projectionMatrix(2, 2) = 0.0f;
|
||||
_projectionMatrix(2, 3) = 0.0f;
|
||||
|
||||
_projectionMatrix(3, 0) = -1.0f;
|
||||
_projectionMatrix(3, 1) = -1.0f;
|
||||
_projectionMatrix(3, 2) = 0.0f;
|
||||
_projectionMatrix(3, 3) = 1.0f;
|
||||
|
||||
// Directly apply changes when we are active.
|
||||
if (isActive()) {
|
||||
applyViewport();
|
||||
applyProjectionMatrix();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
} // End of namespace OpenGL
|
||||
240
backends/graphics/opengl/framebuffer.h
Normal file
240
backends/graphics/opengl/framebuffer.h
Normal file
@@ -0,0 +1,240 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_FRAMEBUFFER_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_FRAMEBUFFER_H
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
|
||||
#include "math/matrix4.h"
|
||||
|
||||
#include "common/rotationmode.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class Pipeline;
|
||||
|
||||
/**
|
||||
* Object describing a framebuffer OpenGL can render to.
|
||||
*/
|
||||
class Framebuffer {
|
||||
public:
|
||||
Framebuffer();
|
||||
virtual ~Framebuffer() {};
|
||||
|
||||
public:
|
||||
enum BlendMode {
|
||||
/**
|
||||
* Newly drawn pixels overwrite the existing contents of the framebuffer
|
||||
* without mixing with them.
|
||||
*/
|
||||
kBlendModeDisabled,
|
||||
|
||||
/**
|
||||
* Newly drawn pixels overwrite the existing contents of the framebuffer
|
||||
* without mixing with them. Alpha channel is discarded.
|
||||
*/
|
||||
kBlendModeOpaque,
|
||||
|
||||
/**
|
||||
* Newly drawn pixels mix with the framebuffer based on their alpha value
|
||||
* for transparency.
|
||||
*/
|
||||
kBlendModeTraditionalTransparency,
|
||||
|
||||
/**
|
||||
* Newly drawn pixels mix with the framebuffer based on their alpha value
|
||||
* for transparency.
|
||||
*
|
||||
* Requires the image data being drawn to have its color values pre-multiplied
|
||||
* with the alpha value.
|
||||
*/
|
||||
kBlendModePremultipliedTransparency,
|
||||
|
||||
/**
|
||||
* Newly drawn pixels add to the destination value.
|
||||
*/
|
||||
kBlendModeAdditive,
|
||||
|
||||
/**
|
||||
* Newly drawn pixels mask out existing pixels based on the alpha value and
|
||||
* add inversions of the pixels based on the color.
|
||||
*/
|
||||
kBlendModeMaskAlphaAndInvertByColor,
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the clear color of the framebuffer.
|
||||
*/
|
||||
void setClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
|
||||
|
||||
/**
|
||||
* Enable/disable GL_BLEND.
|
||||
*/
|
||||
void enableBlend(BlendMode mode);
|
||||
|
||||
/**
|
||||
* Enable/disable GL_SCISSOR_TEST.
|
||||
*/
|
||||
void enableScissorTest(bool enable);
|
||||
|
||||
/**
|
||||
* Set scissor box dimensions.
|
||||
*/
|
||||
void setScissorBox(GLint x, GLint y, GLsizei w, GLsizei h);
|
||||
|
||||
/**
|
||||
* Obtain projection matrix of the framebuffer.
|
||||
*/
|
||||
const Math::Matrix4 &getProjectionMatrix() const { return _projectionMatrix; }
|
||||
|
||||
enum CopyMask {
|
||||
kCopyMaskClearColor = (1 << 0),
|
||||
kCopyMaskBlendState = (1 << 1),
|
||||
kCopyMaskScissorState = (1 << 2),
|
||||
kCopyMaskScissorBox = (1 << 4),
|
||||
|
||||
kCopyMaskAll = kCopyMaskClearColor | kCopyMaskBlendState |
|
||||
kCopyMaskScissorState | kCopyMaskScissorBox,
|
||||
};
|
||||
|
||||
/**
|
||||
* Copy rendering state from another framebuffer
|
||||
*/
|
||||
void copyRenderStateFrom(const Framebuffer &other, uint copyMask);
|
||||
|
||||
protected:
|
||||
bool isActive() const { return _pipeline != nullptr; }
|
||||
|
||||
GLint _viewport[4];
|
||||
void applyViewport();
|
||||
|
||||
Math::Matrix4 _projectionMatrix;
|
||||
void applyProjectionMatrix();
|
||||
|
||||
/**
|
||||
* Activate framebuffer.
|
||||
*
|
||||
* This is supposed to set all state associated with the framebuffer.
|
||||
*/
|
||||
virtual void activateInternal() = 0;
|
||||
|
||||
/**
|
||||
* Deactivate framebuffer.
|
||||
*
|
||||
* This is supposed to make any cleanup required when unbinding the
|
||||
* framebuffer.
|
||||
*/
|
||||
virtual void deactivateInternal() {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Set the size of the target buffer.
|
||||
*/
|
||||
virtual bool setSize(uint width, uint height) = 0;
|
||||
|
||||
/**
|
||||
* Accessor to activate framebuffer for pipeline.
|
||||
*/
|
||||
void activate(Pipeline *pipeline);
|
||||
|
||||
/**
|
||||
* Accessor to deactivate framebuffer from pipeline.
|
||||
*/
|
||||
void deactivate();
|
||||
|
||||
private:
|
||||
Pipeline *_pipeline;
|
||||
|
||||
GLfloat _clearColor[4];
|
||||
void applyClearColor();
|
||||
|
||||
BlendMode _blendState;
|
||||
void applyBlendState();
|
||||
|
||||
bool _scissorTestState;
|
||||
void applyScissorTestState();
|
||||
|
||||
GLint _scissorBox[4];
|
||||
void applyScissorBox();
|
||||
};
|
||||
|
||||
/**
|
||||
* Default back buffer implementation.
|
||||
*/
|
||||
class Backbuffer : public Framebuffer {
|
||||
public:
|
||||
/**
|
||||
* Set the size of the back buffer.
|
||||
*/
|
||||
bool setSize(uint width, uint height) override;
|
||||
|
||||
protected:
|
||||
void activateInternal() override;
|
||||
};
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
class Texture;
|
||||
|
||||
/**
|
||||
* Render to texture framebuffer implementation.
|
||||
*
|
||||
* This target allows to render to a texture, which can then be used for
|
||||
* further rendering.
|
||||
*/
|
||||
class TextureTarget : public Framebuffer {
|
||||
public:
|
||||
TextureTarget();
|
||||
~TextureTarget() override;
|
||||
|
||||
/**
|
||||
* Notify that the GL context is about to be destroyed.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Notify that the GL context has been created.
|
||||
*/
|
||||
void create();
|
||||
|
||||
/**
|
||||
* Set size of the texture target.
|
||||
*/
|
||||
bool setSize(uint width, uint height) override;
|
||||
|
||||
/**
|
||||
* Query pointer to underlying GL texture.
|
||||
*/
|
||||
Texture *getTexture() const { return _texture; }
|
||||
|
||||
protected:
|
||||
void activateInternal() override;
|
||||
|
||||
private:
|
||||
Texture *_texture;
|
||||
GLuint _glFBO;
|
||||
bool _needUpdate;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
2066
backends/graphics/opengl/opengl-graphics.cpp
Normal file
2066
backends/graphics/opengl/opengl-graphics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
538
backends/graphics/opengl/opengl-graphics.h
Normal file
538
backends/graphics/opengl/opengl-graphics.h
Normal file
@@ -0,0 +1,538 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_OPENGL_GRAPHICS_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_OPENGL_GRAPHICS_H
|
||||
|
||||
#include "backends/graphics/opengl/framebuffer.h"
|
||||
#include "backends/graphics/windowed.h"
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "common/frac.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/ustr.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Graphics {
|
||||
class Font;
|
||||
} // End of namespace Graphics
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
// HACK: We use glColor in the OSD code. This might not be working on GL ES but
|
||||
// we still enable it because Tizen already shipped with it. Also, the
|
||||
// SurfaceSDL backend enables it and disabling it can cause issues in sdl.cpp.
|
||||
#define USE_OSD 1
|
||||
|
||||
class Surface;
|
||||
class Pipeline;
|
||||
#if !USE_FORCED_GLES
|
||||
class LibRetroPipeline;
|
||||
#endif
|
||||
#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
|
||||
class Renderer3D;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
GFX_OPENGL = 0
|
||||
};
|
||||
|
||||
class OpenGLGraphicsManager : virtual public WindowedGraphicsManager {
|
||||
public:
|
||||
OpenGLGraphicsManager();
|
||||
virtual ~OpenGLGraphicsManager();
|
||||
|
||||
// GraphicsManager API
|
||||
bool hasFeature(OSystem::Feature f) const override;
|
||||
void setFeatureState(OSystem::Feature f, bool enable) override;
|
||||
bool getFeatureState(OSystem::Feature f) const override;
|
||||
|
||||
const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
|
||||
int getDefaultGraphicsMode() const override;
|
||||
bool setGraphicsMode(int mode, uint flags = OSystem::kGfxModeNoFlags) override;
|
||||
int getGraphicsMode() const override;
|
||||
|
||||
#ifdef USE_RGB_COLOR
|
||||
Graphics::PixelFormat getScreenFormat() const override;
|
||||
Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
|
||||
#endif
|
||||
|
||||
const OSystem::GraphicsMode *getSupportedStretchModes() const override;
|
||||
int getDefaultStretchMode() const override;
|
||||
bool setStretchMode(int mode) override;
|
||||
int getStretchMode() const override;
|
||||
|
||||
#ifdef USE_SCALERS
|
||||
uint getDefaultScaler() const override;
|
||||
uint getDefaultScaleFactor() const override;
|
||||
bool setScaler(uint mode, int factor) override;
|
||||
uint getScaler() const override;
|
||||
uint getScaleFactor() const override;
|
||||
#endif
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
bool setShader(const Common::Path &fileNode) override;
|
||||
#endif
|
||||
|
||||
void beginGFXTransaction() override;
|
||||
OSystem::TransactionError endGFXTransaction() override;
|
||||
|
||||
int getScreenChangeID() const override;
|
||||
|
||||
void initSize(uint width, uint height, const Graphics::PixelFormat *format) override;
|
||||
|
||||
int16 getWidth() const override;
|
||||
int16 getHeight() const override;
|
||||
|
||||
void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override;
|
||||
void fillScreen(uint32 col) override;
|
||||
void fillScreen(const Common::Rect &r, uint32 col) override;
|
||||
|
||||
void updateScreen() override;
|
||||
void presentBuffer() override;
|
||||
|
||||
Graphics::Surface *lockScreen() override;
|
||||
void unlockScreen() override;
|
||||
|
||||
void setFocusRectangle(const Common::Rect& rect) override;
|
||||
void clearFocusRectangle() override;
|
||||
|
||||
int16 getOverlayWidth() const override;
|
||||
int16 getOverlayHeight() const override;
|
||||
void showOverlay(bool inGUI) override;
|
||||
void hideOverlay() override;
|
||||
|
||||
Graphics::PixelFormat getOverlayFormat() const override;
|
||||
|
||||
void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
|
||||
void clearOverlay() override;
|
||||
void grabOverlay(Graphics::Surface &surface) const override;
|
||||
|
||||
void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask) override;
|
||||
void setCursorPalette(const byte *colors, uint start, uint num) override;
|
||||
|
||||
void displayMessageOnOSD(const Common::U32String &msg) override;
|
||||
void displayActivityIconOnOSD(const Graphics::Surface *icon) override;
|
||||
|
||||
// PaletteManager interface
|
||||
void setPalette(const byte *colors, uint start, uint num) override;
|
||||
void grabPalette(byte *colors, uint start, uint num) const override;
|
||||
|
||||
protected:
|
||||
void renderCursor();
|
||||
|
||||
/**
|
||||
* Whether a GLES or GLES2 context is active.
|
||||
*/
|
||||
bool isGLESContext() const { return OpenGLContext.type == kContextGLES || OpenGLContext.type == kContextGLES2; }
|
||||
|
||||
/**
|
||||
* Notify the manager of a OpenGL context change. This should be the first
|
||||
* thing to call after you created an OpenGL (ES) context!
|
||||
*
|
||||
* @param type Type of the OpenGL (ES) contexts created.
|
||||
* @param defaultFormat The new default format for the game screen
|
||||
* (this is used for the CLUT8 game screens).
|
||||
* @param defaultFormatAlpha The new default format with an alpha channel
|
||||
* (this is used for the overlay and cursor).
|
||||
*/
|
||||
void notifyContextCreate(
|
||||
ContextType type,
|
||||
Framebuffer *target,
|
||||
const Graphics::PixelFormat &defaultFormat,
|
||||
const Graphics::PixelFormat &defaultFormatAlpha);
|
||||
|
||||
/**
|
||||
* Notify the manager that the OpenGL context is about to be destroyed.
|
||||
* This will free up/reset internal OpenGL related state and *must* be
|
||||
* called whenever a context might be created again after destroying a
|
||||
* context.
|
||||
*/
|
||||
void notifyContextDestroy();
|
||||
|
||||
/**
|
||||
* Create a surface with the specified pixel format.
|
||||
*
|
||||
* @param format The pixel format the Surface object should accept as
|
||||
* input.
|
||||
* @param wantAlpha For CLUT8 surfaces this marks whether an alpha
|
||||
* channel should be used.
|
||||
* @param wantScaler Whether or not a software scaler should be used.
|
||||
* @return A pointer to the surface or nullptr on failure.
|
||||
*/
|
||||
Surface *createSurface(const Graphics::PixelFormat &format, bool wantAlpha = false, bool wantScaler = false, bool wantMask = false);
|
||||
|
||||
//
|
||||
// Transaction support
|
||||
//
|
||||
struct VideoState {
|
||||
VideoState() : valid(false), gameWidth(0), gameHeight(0),
|
||||
#ifdef USE_RGB_COLOR
|
||||
gameFormat(),
|
||||
#endif
|
||||
aspectRatioCorrection(false), graphicsMode(GFX_OPENGL), flags(0),
|
||||
filtering(true), scalerIndex(0), scaleFactor(1), shader() {
|
||||
}
|
||||
|
||||
bool valid;
|
||||
|
||||
uint gameWidth, gameHeight;
|
||||
#ifdef USE_RGB_COLOR
|
||||
Graphics::PixelFormat gameFormat;
|
||||
#endif
|
||||
bool aspectRatioCorrection;
|
||||
int graphicsMode;
|
||||
uint flags;
|
||||
bool filtering;
|
||||
|
||||
uint scalerIndex;
|
||||
int scaleFactor;
|
||||
|
||||
Common::Path shader;
|
||||
|
||||
bool operator==(const VideoState &right) {
|
||||
return gameWidth == right.gameWidth && gameHeight == right.gameHeight
|
||||
#ifdef USE_RGB_COLOR
|
||||
&& gameFormat == right.gameFormat
|
||||
#endif
|
||||
&& aspectRatioCorrection == right.aspectRatioCorrection
|
||||
&& graphicsMode == right.graphicsMode
|
||||
&& flags == right.flags
|
||||
&& filtering == right.filtering
|
||||
&& shader == right.shader;
|
||||
}
|
||||
|
||||
bool operator!=(const VideoState &right) {
|
||||
return !(*this == right);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The currently set up video state.
|
||||
*/
|
||||
VideoState _currentState;
|
||||
|
||||
/**
|
||||
* The old video state used when doing a transaction rollback.
|
||||
*/
|
||||
VideoState _oldState;
|
||||
|
||||
protected:
|
||||
enum TransactionMode {
|
||||
kTransactionNone = 0,
|
||||
kTransactionActive = 1,
|
||||
kTransactionRollback = 2
|
||||
};
|
||||
|
||||
TransactionMode getTransactionMode() const { return _transactionMode; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* The current transaction mode.
|
||||
*/
|
||||
TransactionMode _transactionMode;
|
||||
|
||||
/**
|
||||
* The current screen change ID.
|
||||
*/
|
||||
int _screenChangeID;
|
||||
|
||||
/**
|
||||
* The current stretch mode.
|
||||
*/
|
||||
int _stretchMode;
|
||||
|
||||
/**
|
||||
* Scaled version of _gameScreenShakeXOffset and _gameScreenShakeYOffset (as a Common::Point)
|
||||
*/
|
||||
Common::Point _shakeOffsetScaled;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Set up the requested video mode. This takes parameters which describe
|
||||
* what resolution the game screen requests (this is possibly aspect ratio
|
||||
* corrected!).
|
||||
*
|
||||
* A sub-class should take these parameters as hints. It might very well
|
||||
* set up a mode which it thinks suites the situation best.
|
||||
*
|
||||
* @parma requestedWidth This is the requested actual game screen width.
|
||||
* @param requestedHeight This is the requested actual game screen height.
|
||||
* @param resizable This indicates that the window should not be resized because we can't handle it.
|
||||
* @param antialiasing This is the requested antialiasing level.
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, bool resizable, int antialiasing) = 0;
|
||||
|
||||
bool loadShader(const Common::Path &fileName);
|
||||
|
||||
/**
|
||||
* Refresh the screen contents.
|
||||
*/
|
||||
virtual void refreshScreen() = 0;
|
||||
|
||||
/**
|
||||
* Saves a screenshot of the entire window, excluding window decorations.
|
||||
*
|
||||
* @param filename The output filename.
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool saveScreenshot(const Common::Path &filename) const;
|
||||
|
||||
// Do not hide the argument-less saveScreenshot from the base class
|
||||
using WindowedGraphicsManager::saveScreenshot;
|
||||
|
||||
private:
|
||||
//
|
||||
// OpenGL utilities
|
||||
//
|
||||
|
||||
/**
|
||||
* Initialize the active context for use.
|
||||
*/
|
||||
void initializeGLContext();
|
||||
|
||||
/**
|
||||
* OpenGL pipeline used for rendering.
|
||||
*/
|
||||
Pipeline *_pipeline;
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
/**
|
||||
* OpenGL pipeline used for post-processing.
|
||||
*/
|
||||
LibRetroPipeline *_libretroPipeline;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Try to determine the internal parameters for a given pixel format.
|
||||
*
|
||||
* @return true when the format can be used, false otherwise.
|
||||
*/
|
||||
bool getGLPixelFormat(const Graphics::PixelFormat &pixelFormat, GLenum &glIntFormat, GLenum &glFormat, GLenum &glType) const;
|
||||
|
||||
bool gameNeedsAspectRatioCorrection() const override;
|
||||
int getGameRenderScale() const override;
|
||||
void recalculateDisplayAreas() override;
|
||||
void handleResizeImpl(const int width, const int height) override;
|
||||
|
||||
void updateTextureSettings();
|
||||
|
||||
Pipeline *getPipeline() const { return _pipeline; }
|
||||
|
||||
/**
|
||||
* The default pixel format of the backend.
|
||||
*/
|
||||
Graphics::PixelFormat _defaultFormat;
|
||||
|
||||
/**
|
||||
* The default pixel format with an alpha channel.
|
||||
*/
|
||||
Graphics::PixelFormat _defaultFormatAlpha;
|
||||
|
||||
/**
|
||||
* Render target.
|
||||
*/
|
||||
Framebuffer *_targetBuffer;
|
||||
|
||||
/**
|
||||
* The rendering surface for the virtual game screen.
|
||||
*/
|
||||
Surface *_gameScreen;
|
||||
|
||||
#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
|
||||
/**
|
||||
* The rendering helper for 3D games.
|
||||
*/
|
||||
Renderer3D *_renderer3d;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The game palette if in CLUT8 mode.
|
||||
*/
|
||||
byte _gamePalette[3 * 256];
|
||||
|
||||
//
|
||||
// Overlay
|
||||
//
|
||||
|
||||
/**
|
||||
* The rendering surface for the overlay.
|
||||
*/
|
||||
Surface *_overlay;
|
||||
|
||||
//
|
||||
// Cursor
|
||||
//
|
||||
|
||||
/**
|
||||
* Set up the correct cursor palette.
|
||||
*/
|
||||
void updateCursorPalette();
|
||||
|
||||
/**
|
||||
* The rendering surface for the mouse cursor.
|
||||
*/
|
||||
Surface *_cursor;
|
||||
|
||||
/**
|
||||
* The rendering surface for the opacity and inversion mask (if any)
|
||||
*/
|
||||
Surface *_cursorMask;
|
||||
|
||||
/**
|
||||
* The X offset for the cursor hotspot in unscaled game coordinates.
|
||||
*/
|
||||
int _cursorHotspotX;
|
||||
|
||||
/**
|
||||
* The Y offset for the cursor hotspot in unscaled game coordinates.
|
||||
*/
|
||||
int _cursorHotspotY;
|
||||
|
||||
/**
|
||||
* Recalculate the cursor scaling. Scaling is always done according to
|
||||
* the game screen.
|
||||
*/
|
||||
void recalculateCursorScaling();
|
||||
|
||||
/**
|
||||
* The X offset for the cursor hotspot in scaled game display area
|
||||
* coordinates.
|
||||
*/
|
||||
int _cursorHotspotXScaled;
|
||||
|
||||
/**
|
||||
* The Y offset for the cursor hotspot in scaled game display area
|
||||
* coordinates.
|
||||
*/
|
||||
int _cursorHotspotYScaled;
|
||||
|
||||
/**
|
||||
* The width of the cursor in scaled game display area coordinates.
|
||||
*/
|
||||
float _cursorWidthScaled;
|
||||
|
||||
/**
|
||||
* The height of the cursor in scaled game display area coordinates.
|
||||
*/
|
||||
float _cursorHeightScaled;
|
||||
|
||||
/**
|
||||
* The key color.
|
||||
*/
|
||||
uint32 _cursorKeyColor;
|
||||
|
||||
/**
|
||||
* If true, use key color.
|
||||
*/
|
||||
bool _cursorUseKey;
|
||||
|
||||
/**
|
||||
* Whether no cursor scaling should be applied.
|
||||
*/
|
||||
bool _cursorDontScale;
|
||||
|
||||
/**
|
||||
* Whether the special cursor palette is enabled.
|
||||
*/
|
||||
bool _cursorPaletteEnabled;
|
||||
|
||||
/**
|
||||
* The special cursor palette in case enabled.
|
||||
*/
|
||||
byte _cursorPalette[3 * 256];
|
||||
|
||||
#ifdef USE_SCALERS
|
||||
/**
|
||||
* The list of scaler plugins
|
||||
*/
|
||||
const PluginList &_scalerPlugins;
|
||||
#endif
|
||||
|
||||
#ifdef USE_OSD
|
||||
//
|
||||
// OSD
|
||||
//
|
||||
protected:
|
||||
/**
|
||||
* Returns the font used for on screen display
|
||||
*/
|
||||
virtual const Graphics::Font *getFontOSD() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Request for the OSD icon surface to be updated.
|
||||
*/
|
||||
bool _osdMessageChangeRequest;
|
||||
|
||||
/**
|
||||
* The next OSD message.
|
||||
*
|
||||
* If this value is not empty, the OSD message will be set
|
||||
* to it on the next frame.
|
||||
*/
|
||||
Common::U32String _osdMessageNextData;
|
||||
|
||||
/**
|
||||
* Set the OSD message surface with the value of the next OSD message.
|
||||
*/
|
||||
void osdMessageUpdateSurface();
|
||||
|
||||
/**
|
||||
* The OSD message's contents.
|
||||
*/
|
||||
Surface *_osdMessageSurface;
|
||||
|
||||
/**
|
||||
* Current opacity level of the OSD message.
|
||||
*/
|
||||
uint8 _osdMessageAlpha;
|
||||
|
||||
/**
|
||||
* When fading the OSD message has started.
|
||||
*/
|
||||
uint32 _osdMessageFadeStartTime;
|
||||
|
||||
enum {
|
||||
kOSDMessageFadeOutDelay = 2 * 1000,
|
||||
kOSDMessageFadeOutDuration = 500,
|
||||
kOSDMessageInitialAlpha = 80
|
||||
};
|
||||
|
||||
/**
|
||||
* The OSD background activity icon's contents.
|
||||
*/
|
||||
Surface *_osdIconSurface;
|
||||
|
||||
enum {
|
||||
kOSDIconTopMargin = 10,
|
||||
kOSDIconRightMargin = 10
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
48
backends/graphics/opengl/pipelines/clut8.cpp
Normal file
48
backends/graphics/opengl/pipelines/clut8.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 "backends/graphics/opengl/pipelines/clut8.h"
|
||||
#include "backends/graphics/opengl/shader.h"
|
||||
#include "backends/graphics/opengl/framebuffer.h"
|
||||
#include "graphics/opengl/debug.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
CLUT8LookUpPipeline::CLUT8LookUpPipeline()
|
||||
: ShaderPipeline(ShaderMan.query(ShaderManager::kCLUT8LookUp)), _paletteTexture(nullptr) {
|
||||
}
|
||||
|
||||
void CLUT8LookUpPipeline::drawTextureInternal(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) {
|
||||
assert(isActive());
|
||||
|
||||
// Set the palette texture.
|
||||
GL_CALL(glActiveTexture(GL_TEXTURE1));
|
||||
if (_paletteTexture) {
|
||||
_paletteTexture->bind();
|
||||
}
|
||||
|
||||
GL_CALL(glActiveTexture(GL_TEXTURE0));
|
||||
ShaderPipeline::drawTextureInternal(texture, coordinates, texcoords);
|
||||
}
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
} // End of namespace OpenGL
|
||||
46
backends/graphics/opengl/pipelines/clut8.h
Normal file
46
backends/graphics/opengl/pipelines/clut8.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_PIPELINES_CLUT8_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_CLUT8_H
|
||||
|
||||
#include "backends/graphics/opengl/pipelines/shader.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
class CLUT8LookUpPipeline : public ShaderPipeline {
|
||||
public:
|
||||
CLUT8LookUpPipeline();
|
||||
|
||||
void setPaletteTexture(const Texture *paletteTexture) { _paletteTexture = paletteTexture; }
|
||||
|
||||
protected:
|
||||
void drawTextureInternal(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) override;
|
||||
|
||||
private:
|
||||
const Texture *_paletteTexture;
|
||||
};
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
88
backends/graphics/opengl/pipelines/fixed.cpp
Normal file
88
backends/graphics/opengl/pipelines/fixed.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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 "backends/graphics/opengl/pipelines/fixed.h"
|
||||
#include "graphics/opengl/debug.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
#if !USE_FORCED_GLES2
|
||||
void FixedPipeline::activateInternal() {
|
||||
Pipeline::activateInternal();
|
||||
|
||||
// Disable 3D properties.
|
||||
GL_CALL(glDisable(GL_CULL_FACE));
|
||||
GL_CALL(glDisable(GL_DEPTH_TEST));
|
||||
GL_CALL(glDisable(GL_DITHER));
|
||||
|
||||
GL_CALL(glDisable(GL_LIGHTING));
|
||||
GL_CALL(glDisable(GL_FOG));
|
||||
GL_CALL(glShadeModel(GL_FLAT));
|
||||
GL_CALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
|
||||
|
||||
GL_CALL(glEnableClientState(GL_VERTEX_ARRAY));
|
||||
GL_CALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
if (OpenGLContext.multitextureSupported) {
|
||||
GL_CALL(glActiveTexture(GL_TEXTURE0));
|
||||
}
|
||||
#endif
|
||||
GL_CALL(glEnable(GL_TEXTURE_2D));
|
||||
GL_CALL(glColor4f(_r, _g, _b, _a));
|
||||
}
|
||||
|
||||
void FixedPipeline::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
|
||||
_r = r;
|
||||
_g = g;
|
||||
_b = b;
|
||||
_a = a;
|
||||
|
||||
if (isActive()) {
|
||||
GL_CALL(glColor4f(r, g, b, a));
|
||||
}
|
||||
}
|
||||
|
||||
void FixedPipeline::drawTextureInternal(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) {
|
||||
assert(isActive());
|
||||
|
||||
texture.bind();
|
||||
|
||||
GL_CALL(glTexCoordPointer(2, GL_FLOAT, 0, texcoords));
|
||||
GL_CALL(glVertexPointer(2, GL_FLOAT, 0, coordinates));
|
||||
GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
|
||||
}
|
||||
|
||||
void FixedPipeline::setProjectionMatrix(const Math::Matrix4 &projectionMatrix) {
|
||||
assert(isActive());
|
||||
|
||||
GL_CALL(glMatrixMode(GL_PROJECTION));
|
||||
GL_CALL(glLoadMatrixf(projectionMatrix.getData()));
|
||||
|
||||
GL_CALL(glMatrixMode(GL_MODELVIEW));
|
||||
GL_CALL(glLoadIdentity());
|
||||
|
||||
GL_CALL(glMatrixMode(GL_TEXTURE));
|
||||
GL_CALL(glLoadIdentity());
|
||||
}
|
||||
#endif // !USE_FORCED_GLES2
|
||||
|
||||
} // End of namespace OpenGL
|
||||
48
backends/graphics/opengl/pipelines/fixed.h
Normal file
48
backends/graphics/opengl/pipelines/fixed.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_PIPELINES_FIXED_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_FIXED_H
|
||||
|
||||
#include "backends/graphics/opengl/pipelines/pipeline.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
#if !USE_FORCED_GLES2
|
||||
class FixedPipeline : public Pipeline {
|
||||
public:
|
||||
FixedPipeline() : _r(0.f), _g(0.f), _b(0.f), _a(0.f) {}
|
||||
|
||||
void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) override;
|
||||
|
||||
void setProjectionMatrix(const Math::Matrix4 &projectionMatrix) override;
|
||||
|
||||
protected:
|
||||
void activateInternal() override;
|
||||
void drawTextureInternal(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) override;
|
||||
|
||||
GLfloat _r, _g, _b, _a;
|
||||
};
|
||||
#endif // !USE_FORCED_GLES2
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
1075
backends/graphics/opengl/pipelines/libretro.cpp
Normal file
1075
backends/graphics/opengl/pipelines/libretro.cpp
Normal file
File diff suppressed because it is too large
Load Diff
277
backends/graphics/opengl/pipelines/libretro.h
Normal file
277
backends/graphics/opengl/pipelines/libretro.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_H
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
#include "backends/graphics/opengl/pipelines/shader.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/fs.h"
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
namespace LibRetro {
|
||||
struct ShaderPreset;
|
||||
struct ShaderPass;
|
||||
} // End of namespace LibRetro
|
||||
|
||||
class TextureTarget;
|
||||
class LibRetroTextureTarget;
|
||||
|
||||
/**
|
||||
* Pipeline implementation using Libretro shader presets.
|
||||
*/
|
||||
class LibRetroPipeline : public Pipeline {
|
||||
public:
|
||||
LibRetroPipeline();
|
||||
~LibRetroPipeline() override;
|
||||
|
||||
void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) override;
|
||||
void setProjectionMatrix(const Math::Matrix4 &projectionMatrix) override;
|
||||
|
||||
bool open(const Common::Path &shaderPath, Common::SearchSet &archSet);
|
||||
void close();
|
||||
|
||||
/* Called by OpenGLGraphicsManager */
|
||||
void enableLinearFiltering(bool enabled) { _linearFiltering = enabled; }
|
||||
void setRotation(Common::RotationMode rotation) { if (_rotation != rotation) { _rotation = rotation; setPipelineState(); } }
|
||||
/* Called by OpenGLGraphicsManager to setup the internal objects sizes */
|
||||
void setDisplaySizes(uint inputWidth, uint inputHeight, const Common::Rect &outputRect);
|
||||
/* Called by OpenGLGraphicsManager to indicate that next draws need to be scaled. */
|
||||
void beginScaling();
|
||||
/* Called by OpenGLGraphicsManager to indicate that next draws don't need to be scaled.
|
||||
* This must be called to execute scaling. */
|
||||
void finishScaling();
|
||||
bool isAnimated() const { return _isAnimated; }
|
||||
|
||||
static bool isSupportedByContext() {
|
||||
return OpenGLContext.shadersSupported
|
||||
&& OpenGLContext.multitextureSupported
|
||||
&& OpenGLContext.framebufferObjectSupported;
|
||||
}
|
||||
private:
|
||||
void activateInternal() override;
|
||||
void deactivateInternal() override;
|
||||
void drawTextureInternal(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) override;
|
||||
|
||||
bool loadTextures(Common::SearchSet &archSet);
|
||||
bool loadPasses(Common::SearchSet &archSet);
|
||||
|
||||
void setPipelineState();
|
||||
bool setupFBOs();
|
||||
void setupPassUniforms(const uint id);
|
||||
void setShaderTexUniforms(const Common::String &prefix, Shader *shader, const Texture &texture);
|
||||
|
||||
/* Pipelines used to draw all layers
|
||||
* First before the scaler then after it to draw on screen
|
||||
*/
|
||||
ShaderPipeline _inputPipeline;
|
||||
ShaderPipeline _outputPipeline;
|
||||
bool _needsScaling;
|
||||
|
||||
const LibRetro::ShaderPreset *_shaderPreset;
|
||||
|
||||
uint _inputWidth;
|
||||
uint _inputHeight;
|
||||
Common::Rect _outputRect;
|
||||
|
||||
bool _linearFiltering;
|
||||
Common::RotationMode _rotation;
|
||||
|
||||
/* Determines if preset depends on frameCount or from previous frames */
|
||||
bool _isAnimated;
|
||||
uint _frameCount;
|
||||
|
||||
Common::Array<LibRetroTextureTarget> _inputTargets;
|
||||
uint _currentTarget;
|
||||
|
||||
struct LibRetroTexture {
|
||||
LibRetroTexture() : textureData(nullptr), glTexture(nullptr) {}
|
||||
LibRetroTexture(Graphics::Surface *tD, Texture *glTex) : textureData(tD), glTexture(glTex) {}
|
||||
|
||||
Common::String id;
|
||||
Graphics::Surface *textureData;
|
||||
Texture *glTexture;
|
||||
};
|
||||
LibRetroTexture loadTexture(const Common::Path &fileName, Common::Archive *container, Common::SearchSet &archSet);
|
||||
|
||||
typedef Common::Array<LibRetroTexture> TextureArray;
|
||||
TextureArray _textures;
|
||||
|
||||
struct Pass {
|
||||
Pass()
|
||||
: shaderPass(nullptr), shader(nullptr), target(nullptr), texCoords(), texSamplers(),
|
||||
inputTexture(nullptr), vertexCoord(), hasFrameCount(false), prevCount(0) {}
|
||||
Pass(const LibRetro::ShaderPass *sP, Shader *s, TextureTarget *t)
|
||||
: shaderPass(sP), shader(s), target(t), texCoords(), texSamplers(),
|
||||
inputTexture(nullptr), vertexCoord(), hasFrameCount(false), prevCount(0) {}
|
||||
|
||||
const LibRetro::ShaderPass *shaderPass;
|
||||
Shader *shader;
|
||||
TextureTarget *target;
|
||||
|
||||
/**
|
||||
* Description of texture coordinates bound to attribute.
|
||||
*/
|
||||
struct TexCoordAttribute {
|
||||
/**
|
||||
* Attribute name to bind data to.
|
||||
*/
|
||||
Common::String name;
|
||||
|
||||
enum Type {
|
||||
/**
|
||||
* 'index' denotes the 'index'th shader texture's coordinates.
|
||||
*/
|
||||
kTypeTexture,
|
||||
|
||||
/**
|
||||
* 'index' denotes the texture coordinates given to pass 'index'.
|
||||
*/
|
||||
kTypePass,
|
||||
|
||||
/**
|
||||
* 'index' denotes the texture coordinates of the 'index'th previous frame.
|
||||
*/
|
||||
kTypePrev
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the attribute.
|
||||
*/
|
||||
Type type;
|
||||
|
||||
/**
|
||||
* Index for the texture coordinates to use.
|
||||
*/
|
||||
uint index;
|
||||
|
||||
TexCoordAttribute() : name(), type(), index() {}
|
||||
TexCoordAttribute(const Common::String &n, Type t, uint i) : name(n), type(t), index(i) {}
|
||||
};
|
||||
|
||||
typedef Common::Array<TexCoordAttribute> TexCoordAttributeArray;
|
||||
TexCoordAttributeArray texCoords;
|
||||
|
||||
/**
|
||||
* Build the 'texCoords' array.
|
||||
*
|
||||
* @param id Identifier of the current pass.
|
||||
*/
|
||||
void buildTexCoords(const uint id, const Common::StringArray &aliases);
|
||||
|
||||
void addTexCoord(const Common::String &prefix, const TexCoordAttribute::Type type, const uint index);
|
||||
|
||||
/**
|
||||
* Description of a texture sampler.
|
||||
*/
|
||||
struct TextureSampler {
|
||||
/**
|
||||
* Texture unit to use.
|
||||
*/
|
||||
uint unit;
|
||||
|
||||
enum Type {
|
||||
/**
|
||||
* 'index' denotes the 'index'th shader texture.
|
||||
*/
|
||||
kTypeTexture,
|
||||
|
||||
/**
|
||||
* 'index' denotes the input to pass 'index'.
|
||||
*/
|
||||
kTypePass,
|
||||
|
||||
/**
|
||||
* 'index' denotes the input of the 'index'th previous frame.
|
||||
*/
|
||||
kTypePrev
|
||||
};
|
||||
|
||||
/**
|
||||
* Source type of the texture to bind.
|
||||
*/
|
||||
Type type;
|
||||
|
||||
/**
|
||||
* Index of the texture.
|
||||
*/
|
||||
uint index;
|
||||
|
||||
TextureSampler() : unit(), type(), index() {}
|
||||
TextureSampler(uint u, Type t, uint i) : unit(u), type(t), index(i) {}
|
||||
};
|
||||
|
||||
typedef Common::Array<TextureSampler> TextureSamplerArray;
|
||||
TextureSamplerArray texSamplers;
|
||||
|
||||
/**
|
||||
* Build the 'texSamplers' array.
|
||||
*
|
||||
* @param id Identifier of the current pass.
|
||||
* @param textures Array of shader textures available.
|
||||
*/
|
||||
void buildTexSamplers(const uint id, const TextureArray &textures, const Common::StringArray &aliases);
|
||||
|
||||
bool addTexSampler(const Common::String &name, uint *unit, const TextureSampler::Type type, const uint index, const bool prefixIsId = false);
|
||||
|
||||
/**
|
||||
* Input texture of the pass.
|
||||
*/
|
||||
const Texture *inputTexture;
|
||||
|
||||
/**
|
||||
* Vertex coordinates used for drawing.
|
||||
*/
|
||||
GLfloat vertexCoord[2*4];
|
||||
|
||||
/**
|
||||
* Whether the shader has a FrameCount uniform or not
|
||||
* Allows to speed up if it is not here
|
||||
*/
|
||||
bool hasFrameCount;
|
||||
|
||||
/**
|
||||
* The number of previous frames this pass needs
|
||||
*/
|
||||
uint prevCount;
|
||||
};
|
||||
|
||||
typedef Common::Array<Pass> PassArray;
|
||||
PassArray _passes;
|
||||
|
||||
void renderPass(const Pass &pass);
|
||||
void renderPassSetupCoordinates(const Pass &pass);
|
||||
void renderPassSetupTextures(const Pass &pass);
|
||||
};
|
||||
|
||||
} // End of namespace OpenGL
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
#endif
|
||||
573
backends/graphics/opengl/pipelines/libretro/parser.cpp
Normal file
573
backends/graphics/opengl/pipelines/libretro/parser.cpp
Normal file
@@ -0,0 +1,573 @@
|
||||
/* 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 "graphics/opengl/system_headers.h"
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
#include "backends/graphics/opengl/pipelines/libretro/parser.h"
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/tokenizer.h"
|
||||
#include "common/ptr.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace OpenGL {
|
||||
namespace LibRetro {
|
||||
|
||||
class PresetParser {
|
||||
public:
|
||||
ShaderPreset *parseStream(Common::SeekableReadStream &stream);
|
||||
|
||||
const Common::String &getErrorDesc() const { return _errorDesc; }
|
||||
private:
|
||||
bool parsePreset(Common::SeekableReadStream &stream);
|
||||
bool lookUpValue(const Common::String &key, Common::String *value);
|
||||
bool lookUpValue(const Common::String &key, bool *value);
|
||||
bool lookUpValue(const Common::String &key, uint *value);
|
||||
bool lookUpValue(const Common::String &key, float *value);
|
||||
bool lookUpValue(const Common::String &key, FilteringMode *value, const FilteringMode defaultValue);
|
||||
bool lookUpValue(const Common::String &key, ScaleType *value, const ScaleType defaultValue);
|
||||
bool lookUpValueScale(const Common::String &key, float *floatValue, uint *uintValue, const ScaleType scaleType);
|
||||
bool lookUpValue(const Common::String &key, WrapMode *value, const WrapMode defaultValue);
|
||||
|
||||
template<typename T, typename DefaultT>
|
||||
bool lookUpValue(const Common::String &key, T *value, const DefaultT &defaultValue) {
|
||||
if (_entries.contains(key)) {
|
||||
return lookUpValue(key, value);
|
||||
} else {
|
||||
*value = defaultValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool parseTextures();
|
||||
bool parseTexture(const Common::String &id);
|
||||
|
||||
bool parsePasses();
|
||||
bool parsePass(const uint id, const bool isLast);
|
||||
bool parsePassScaleType(const uint id, const bool isLast, ShaderPass *pass);
|
||||
bool parsePassScale(const uint id, ShaderPass *pass);
|
||||
bool computeDefaultScale(const Common::String &key, float *floatValue, uint *uintValue, const ScaleType scaleType);
|
||||
|
||||
bool parseParameters();
|
||||
|
||||
typedef Common::HashMap<Common::String, Common::String> StringMap;
|
||||
StringMap _entries;
|
||||
|
||||
Common::String _errorDesc;
|
||||
|
||||
Common::ScopedPtr<ShaderPreset> _shader;
|
||||
};
|
||||
|
||||
ShaderPreset *PresetParser::parseStream(Common::SeekableReadStream &stream) {
|
||||
_errorDesc.clear();
|
||||
_entries.clear();
|
||||
|
||||
if (!parsePreset(stream)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_shader.reset(new ShaderPreset);
|
||||
if (!parseTextures()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!parsePasses()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!parseParameters()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _shader.release();
|
||||
}
|
||||
|
||||
bool PresetParser::parsePreset(Common::SeekableReadStream &stream) {
|
||||
while (!stream.eos()) {
|
||||
Common::String line = stream.readLine();
|
||||
if (stream.err()) {
|
||||
_errorDesc = "Read error";
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t sharpPos = line.findFirstOf('#');
|
||||
if (sharpPos != line.npos) {
|
||||
// Remove the end of line
|
||||
line.erase(sharpPos);
|
||||
}
|
||||
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool empty = true;
|
||||
for (uint i = 0; i < line.size(); i++) {
|
||||
if (!Common::isSpace(line[i])) {
|
||||
empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty)
|
||||
continue;
|
||||
|
||||
// Split line into key, value pair.
|
||||
Common::String::const_iterator equalIter = Common::find(line.begin(), line.end(), '=');
|
||||
if (equalIter == line.end()) {
|
||||
_errorDesc = "Could not find '=' in line '" + line + '\'';
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String key(line.begin(), equalIter);
|
||||
Common::String value(equalIter + 1);
|
||||
|
||||
key.trim();
|
||||
value.trim();
|
||||
|
||||
// Check whether the value is put in quotation marks. This might be
|
||||
// useful when a path contains a whitespace. But Libretro's is not
|
||||
// mentioning any exact format, but one example for 'textures'
|
||||
// indicates quotes are supported in this place.
|
||||
if (!value.empty() && value[0] == '"') {
|
||||
if (value.size() < 2 || value.lastChar() != '"') {
|
||||
_errorDesc = "Unmatched '\"' for value in line '" + line + '\'';
|
||||
}
|
||||
|
||||
value.deleteLastChar();
|
||||
value.deleteChar(0);
|
||||
}
|
||||
|
||||
_entries[key] = value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PresetParser::lookUpValue(const Common::String &key, Common::String *value) {
|
||||
StringMap::const_iterator iter = _entries.find(key);
|
||||
if (iter != _entries.end()) {
|
||||
*value = iter->_value;
|
||||
return true;
|
||||
} else {
|
||||
_errorDesc = "Missing key '" + key + "'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::lookUpValue(const Common::String &key, bool *value) {
|
||||
StringMap::const_iterator iter = _entries.find(key);
|
||||
if (iter != _entries.end()) {
|
||||
if (Common::parseBool(iter->_value, *value)) {
|
||||
return true;
|
||||
} else {
|
||||
_errorDesc = "Invalid boolean value for key '" + key + "': '" + iter->_value + '\'';
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
_errorDesc = "Missing key '" + key + "'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::lookUpValue(const Common::String &key, uint *value) {
|
||||
StringMap::const_iterator iter = _entries.find(key);
|
||||
if (iter != _entries.end()) {
|
||||
char *endptr;
|
||||
const unsigned long uintVal = strtoul(iter->_value.c_str(), &endptr, 0);
|
||||
// Original libretro is quite laxist with int values and only checks errno
|
||||
// This means that as long as there is some number at start, parsing won't fail
|
||||
if (endptr == iter->_value.c_str() || uintVal >= UINT_MAX) {
|
||||
_errorDesc = "Invalid unsigned integer value for key '" + key + "': '" + iter->_value + '\'';
|
||||
return false;
|
||||
} else {
|
||||
if (*endptr != '\0') {
|
||||
warning("Possibly invalid unsigned integer value for key '%s': '%s'", key.c_str(), iter->_value.c_str());
|
||||
}
|
||||
*value = uintVal;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
_errorDesc = "Missing key '" + key + "'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::lookUpValue(const Common::String &key, float *value) {
|
||||
StringMap::const_iterator iter = _entries.find(key);
|
||||
if (iter != _entries.end()) {
|
||||
char *endptr;
|
||||
const double doubleVal = strtod(iter->_value.c_str(), &endptr);
|
||||
if (*endptr != '\0') {
|
||||
_errorDesc = "Invalid float value for key '" + key + "': '" + iter->_value + '\'';
|
||||
return false;
|
||||
} else {
|
||||
*value = doubleVal;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
_errorDesc = "Missing key '" + key + "'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::lookUpValue(const Common::String &key, FilteringMode *value, const FilteringMode defaultValue) {
|
||||
StringMap::const_iterator iter = _entries.find(key);
|
||||
if (iter != _entries.end()) {
|
||||
bool isLinear;
|
||||
if (Common::parseBool(iter->_value, isLinear)) {
|
||||
*value = isLinear ? kFilteringModeLinear : kFilteringModeNearest;
|
||||
return true;
|
||||
} else {
|
||||
_errorDesc = "Invalid filtering mode for key '" + key + "': '" + iter->_value + '\'';
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*value = defaultValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::lookUpValue(const Common::String &key, ScaleType *value, const ScaleType defaultValue) {
|
||||
StringMap::const_iterator iter = _entries.find(key);
|
||||
if (iter != _entries.end()) {
|
||||
if (iter->_value == "source") {
|
||||
*value = kScaleTypeSource;
|
||||
return true;
|
||||
} else if (iter->_value == "viewport") {
|
||||
*value = kScaleTypeViewport;
|
||||
return true;
|
||||
} else if (iter->_value == "absolute") {
|
||||
*value = kScaleTypeAbsolute;
|
||||
return true;
|
||||
} else {
|
||||
_errorDesc = "Invalid scale type for key '" + key + "': '" + iter->_value + '\'';
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*value = defaultValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::lookUpValueScale(const Common::String &key, float *floatValue, uint *uintValue, const ScaleType scaleType) {
|
||||
switch (scaleType) {
|
||||
case kScaleTypeSource:
|
||||
case kScaleTypeViewport:
|
||||
return lookUpValue(key, floatValue, 1.0f);
|
||||
|
||||
case kScaleTypeAbsolute:
|
||||
return lookUpValue(key, uintValue);
|
||||
|
||||
case kScaleTypeFull:
|
||||
return true;
|
||||
|
||||
default:
|
||||
_errorDesc = "Internal Error: Invalid scale type";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::lookUpValue(const Common::String &key, WrapMode *value, const WrapMode defaultValue) {
|
||||
StringMap::const_iterator iter = _entries.find(key);
|
||||
if (iter != _entries.end()) {
|
||||
if (iter->_value == "clamp_to_border") {
|
||||
*value = kWrapModeBorder;
|
||||
return true;
|
||||
} else if (iter->_value == "clamp_to_edge") {
|
||||
*value = kWrapModeEdge;
|
||||
return true;
|
||||
} else if (iter->_value == "repeat") {
|
||||
*value = kWrapModeRepeat;
|
||||
return true;
|
||||
} else if (iter->_value == "mirrored_repeat") {
|
||||
*value = kWrapModeMirroredRepeat;
|
||||
return true;
|
||||
} else {
|
||||
_errorDesc = "Invalid wrap mode for key '" + key + "': '" + iter->_value + '\'';
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*value = defaultValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::parseTextures() {
|
||||
Common::String textures;
|
||||
if (!lookUpValue("textures", &textures)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse all texture information from preset.
|
||||
Common::StringTokenizer tokenizer(textures, ";");
|
||||
while (!tokenizer.empty()) {
|
||||
if (!parseTexture(tokenizer.nextToken())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PresetParser::parseTexture(const Common::String &id) {
|
||||
Common::String fileName;
|
||||
if (!lookUpValue(id, &fileName)) {
|
||||
_errorDesc = "No file name specified for texture '" + id + '\'';
|
||||
return false;
|
||||
}
|
||||
|
||||
FilteringMode filteringMode;
|
||||
if (!lookUpValue(id + "_linear", &filteringMode, kFilteringModeLinear)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WrapMode wrapMode;
|
||||
if (!lookUpValue(id + "_wrap_mode", &wrapMode, kWrapModeBorder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_shader->textures.push_back(ShaderTexture(id, fileName, filteringMode, wrapMode));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PresetParser::parsePasses() {
|
||||
uint numShaders;
|
||||
if (!lookUpValue("shaders", &numShaders)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint shaderPass = 0; shaderPass < numShaders; ++shaderPass) {
|
||||
if (!parsePass(shaderPass, shaderPass == numShaders - 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define passKey(x) Common::String::format(x "%u", id)
|
||||
bool PresetParser::parsePass(const uint id, const bool isLast) {
|
||||
ShaderPass pass;
|
||||
|
||||
if (!lookUpValue(passKey("shader"), &pass.fileName)) {
|
||||
_errorDesc = Common::String::format("No file name specified for pass '%u'", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookUpValue(passKey("alias"), &pass.alias)) {
|
||||
_errorDesc.clear();
|
||||
pass.alias.clear();
|
||||
}
|
||||
|
||||
if (!lookUpValue(passKey("filter_linear"), &pass.filteringMode, kFilteringModeUnspecified)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookUpValue(passKey("wrap_mode"), &pass.wrapMode, kWrapModeBorder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookUpValue(passKey("mipmap_input"), &pass.mipmapInput, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookUpValue(passKey("float_framebuffer"), &pass.floatFBO, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookUpValue(passKey("srgb_framebuffer"), &pass.srgbFBO, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookUpValue(passKey("frame_count_mod"), &pass.frameCountMod, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parsePassScaleType(id, isLast, &pass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parsePassScale(id, &pass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_shader->passes.push_back(pass);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PresetParser::parsePassScaleType(const uint id, const bool isLast, ShaderPass *pass) {
|
||||
// Parse scale type for the pass.
|
||||
//
|
||||
// This is a little more complicated because it is possible to specify the
|
||||
// scale type per axis. However, a generic scale type overrides the axis
|
||||
// scale types.
|
||||
//
|
||||
// Additionally, the default value for the passes vary. The last pass
|
||||
// defaults to use full size, all other default to source scaling.
|
||||
|
||||
const ScaleType defaultScaleType = isLast ? kScaleTypeFull : kScaleTypeSource;
|
||||
|
||||
if (!lookUpValue(passKey("scale_type_x"), &pass->scaleTypeX, defaultScaleType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookUpValue(passKey("scale_type_y"), &pass->scaleTypeY, defaultScaleType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScaleType scale_type;
|
||||
// Small trick here: lookUpValue never returns kScaleTypeFull
|
||||
if (!lookUpValue(passKey("scale_type"), &scale_type, kScaleTypeFull)) {
|
||||
return false;
|
||||
} else if (scale_type != kScaleTypeFull) {
|
||||
pass->scaleTypeY = pass->scaleTypeX = scale_type;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PresetParser::parsePassScale(const uint id, ShaderPass *pass) {
|
||||
// Parse actual scale value for the pass.
|
||||
//
|
||||
// Like for the scale type, 'scale' overrides 'scale_x'/'scale_y'.
|
||||
if (_entries.contains(passKey("scale"))) {
|
||||
if (!lookUpValueScale(passKey("scale"), &pass->scaleXFloat, &pass->scaleXUint, pass->scaleTypeX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lookUpValueScale(passKey("scale"), &pass->scaleYFloat, &pass->scaleYUint, pass->scaleTypeY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_entries.contains(passKey("scale_x"))) {
|
||||
if (!lookUpValueScale(passKey("scale_x"), &pass->scaleXFloat, &pass->scaleXUint, pass->scaleTypeX)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!computeDefaultScale(passKey("scale_x"), &pass->scaleXFloat, &pass->scaleXUint, pass->scaleTypeX)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_entries.contains(passKey("scale_y"))) {
|
||||
if (!lookUpValueScale(passKey("scale_y"), &pass->scaleYFloat, &pass->scaleYUint, pass->scaleTypeY)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!computeDefaultScale(passKey("scale_y"), &pass->scaleYFloat, &pass->scaleYUint, pass->scaleTypeY)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#undef passKey
|
||||
|
||||
bool PresetParser::computeDefaultScale(const Common::String &key, float *floatValue, uint *uintValue, const ScaleType scaleType) {
|
||||
switch (scaleType) {
|
||||
case kScaleTypeSource:
|
||||
case kScaleTypeViewport:
|
||||
*floatValue = 1.0f;
|
||||
return true;
|
||||
|
||||
case kScaleTypeAbsolute:
|
||||
_errorDesc = "No value specified for scale '" + key + '\'';
|
||||
return false;
|
||||
|
||||
case kScaleTypeFull:
|
||||
return true;
|
||||
|
||||
default:
|
||||
_errorDesc = "Internal Error: Invalid scale type";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetParser::parseParameters() {
|
||||
Common::String parameters;
|
||||
if (!lookUpValue("parameters", ¶meters)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse all texture information from preset.
|
||||
Common::StringTokenizer tokenizer(parameters, ";");
|
||||
while (!tokenizer.empty()) {
|
||||
Common::String key = tokenizer.nextToken();
|
||||
if (_entries.contains(key)) {
|
||||
float value;
|
||||
if (!lookUpValue(key, &value)) {
|
||||
return false;
|
||||
}
|
||||
_shader->parameters[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ShaderPreset *parsePreset(const Common::Path &shaderPreset, Common::SearchSet &archSet) {
|
||||
Common::SeekableReadStream *stream;
|
||||
Common::Archive *container = nullptr;
|
||||
Common::Path basePath;
|
||||
|
||||
// First try SearchMan, then fallback to filesystem
|
||||
if (archSet.hasFile(shaderPreset)) {
|
||||
Common::ArchiveMemberPtr member = archSet.getMember(shaderPreset, &container);
|
||||
stream = member->createReadStream();
|
||||
basePath = shaderPreset.getParent();
|
||||
} else {
|
||||
Common::FSNode fsnode(shaderPreset);
|
||||
if (!fsnode.exists() || !fsnode.isReadable() || fsnode.isDirectory()
|
||||
|| !(stream = fsnode.createReadStream())) {
|
||||
warning("LibRetro Preset Parsing: Invalid file path '%s'", shaderPreset.toString(Common::Path::kNativeSeparator).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
basePath = fsnode.getParent().getPath();
|
||||
}
|
||||
|
||||
PresetParser parser;
|
||||
ShaderPreset *shader = parser.parseStream(*stream);
|
||||
|
||||
delete stream;
|
||||
|
||||
if (!shader) {
|
||||
warning("LibRetro Preset Parsing: Error while parsing file '%s': %s", shaderPreset.toString().c_str(), parser.getErrorDesc().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shader->container = container;
|
||||
shader->basePath = basePath;
|
||||
return shader;
|
||||
}
|
||||
|
||||
} // End of namespace LibRetro
|
||||
} // End of namespace OpenGL
|
||||
#endif // !USE_FORCED_GLES
|
||||
39
backends/graphics/opengl/pipelines/libretro/parser.h
Normal file
39
backends/graphics/opengl/pipelines/libretro/parser.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_PARSER_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_PARSER_H
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
#include "backends/graphics/opengl/pipelines/libretro/types.h"
|
||||
|
||||
namespace OpenGL {
|
||||
namespace LibRetro {
|
||||
|
||||
ShaderPreset *parsePreset(const Common::Path &shaderPreset, Common::SearchSet &archSet);
|
||||
|
||||
} // End of namespace LibRetro
|
||||
} // End of namespace OpenGL
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
#endif
|
||||
132
backends/graphics/opengl/pipelines/libretro/types.h
Normal file
132
backends/graphics/opengl/pipelines/libretro/types.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_TYPES_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_LIBRETRO_TYPES_H
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
#include "graphics/opengl/texture.h"
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
#include "common/str.h"
|
||||
#include "common/array.h"
|
||||
#include "common/fs.h"
|
||||
|
||||
namespace OpenGL {
|
||||
namespace LibRetro {
|
||||
|
||||
typedef Common::HashMap<Common::String, float, Common::CaseSensitiveString_Hash, Common::CaseSensitiveString_EqualTo> UniformsMap;
|
||||
|
||||
enum FilteringMode {
|
||||
kFilteringModeUnspecified,
|
||||
kFilteringModeNearest,
|
||||
kFilteringModeLinear
|
||||
};
|
||||
|
||||
struct ShaderTexture {
|
||||
ShaderTexture() : id(), fileName(), filteringMode(kFilteringModeUnspecified) {}
|
||||
ShaderTexture(const Common::String &i, const Common::String &fN, FilteringMode fM, WrapMode wM)
|
||||
: id(i), fileName(fN), filteringMode(fM), wrapMode(wM) {}
|
||||
|
||||
Common::String id;
|
||||
Common::String fileName;
|
||||
FilteringMode filteringMode;
|
||||
WrapMode wrapMode;
|
||||
};
|
||||
|
||||
enum ScaleType {
|
||||
kScaleTypeSource,
|
||||
kScaleTypeViewport,
|
||||
kScaleTypeAbsolute,
|
||||
kScaleTypeFull
|
||||
};
|
||||
|
||||
inline void applyScale(const ScaleType type,
|
||||
const float source, const float viewport,
|
||||
const float scaleFloat, const uint scaleUint,
|
||||
float *output) {
|
||||
switch (type) {
|
||||
case kScaleTypeSource:
|
||||
*output = source * scaleFloat;
|
||||
break;
|
||||
|
||||
case kScaleTypeViewport:
|
||||
*output = viewport * scaleFloat;
|
||||
break;
|
||||
|
||||
case kScaleTypeAbsolute:
|
||||
*output = scaleUint;
|
||||
break;
|
||||
|
||||
case kScaleTypeFull:
|
||||
*output = viewport;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct ShaderPass {
|
||||
Common::String fileName;
|
||||
Common::String alias;
|
||||
|
||||
FilteringMode filteringMode;
|
||||
WrapMode wrapMode;
|
||||
bool mipmapInput;
|
||||
|
||||
bool floatFBO;
|
||||
bool srgbFBO;
|
||||
|
||||
uint frameCountMod;
|
||||
|
||||
ScaleType scaleTypeX;
|
||||
ScaleType scaleTypeY;
|
||||
|
||||
float scaleXFloat;
|
||||
float scaleYFloat;
|
||||
|
||||
uint scaleXUint;
|
||||
uint scaleYUint;
|
||||
|
||||
void applyScale(const float sourceW, const float sourceH,
|
||||
const float viewportW, const float viewportH,
|
||||
float *outputW, float *outputH) const {
|
||||
OpenGL::LibRetro::applyScale(scaleTypeX, sourceW, viewportW, scaleXFloat, scaleXUint, outputW);
|
||||
OpenGL::LibRetro::applyScale(scaleTypeY, sourceH, viewportH, scaleYFloat, scaleYUint, outputH);
|
||||
}
|
||||
};
|
||||
|
||||
struct ShaderPreset {
|
||||
Common::Archive *container;
|
||||
Common::Path basePath;
|
||||
|
||||
typedef Common::Array<ShaderTexture> TextureArray;
|
||||
TextureArray textures;
|
||||
|
||||
typedef Common::Array<ShaderPass> PassArray;
|
||||
PassArray passes;
|
||||
|
||||
UniformsMap parameters;
|
||||
};
|
||||
|
||||
} // End of namespace LibRetro
|
||||
} // End of namespace OpenGL
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
#endif
|
||||
81
backends/graphics/opengl/pipelines/pipeline.cpp
Normal file
81
backends/graphics/opengl/pipelines/pipeline.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/* 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 "backends/graphics/opengl/pipelines/pipeline.h"
|
||||
#include "backends/graphics/opengl/framebuffer.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
Pipeline *Pipeline::activePipeline = nullptr;
|
||||
|
||||
Pipeline::Pipeline()
|
||||
: _activeFramebuffer(nullptr) {
|
||||
}
|
||||
|
||||
void Pipeline::activate() {
|
||||
if (activePipeline == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activePipeline) {
|
||||
activePipeline->deactivate();
|
||||
}
|
||||
|
||||
activePipeline = this;
|
||||
|
||||
activateInternal();
|
||||
}
|
||||
|
||||
void Pipeline::activateInternal() {
|
||||
if (_activeFramebuffer) {
|
||||
_activeFramebuffer->activate(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Pipeline::deactivate() {
|
||||
assert(isActive());
|
||||
|
||||
deactivateInternal();
|
||||
|
||||
activePipeline = nullptr;
|
||||
}
|
||||
|
||||
void Pipeline::deactivateInternal() {
|
||||
if (_activeFramebuffer) {
|
||||
_activeFramebuffer->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
Framebuffer *Pipeline::setFramebuffer(Framebuffer *framebuffer) {
|
||||
Framebuffer *oldFramebuffer = _activeFramebuffer;
|
||||
if (isActive() && oldFramebuffer) {
|
||||
oldFramebuffer->deactivate();
|
||||
}
|
||||
|
||||
_activeFramebuffer = framebuffer;
|
||||
if (isActive() && _activeFramebuffer) {
|
||||
_activeFramebuffer->activate(this);
|
||||
}
|
||||
|
||||
return oldFramebuffer;
|
||||
}
|
||||
|
||||
} // End of namespace OpenGL
|
||||
167
backends/graphics/opengl/pipelines/pipeline.h
Normal file
167
backends/graphics/opengl/pipelines/pipeline.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_PIPELINES_PIPELINE_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_PIPELINE_H
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
#include "graphics/opengl/texture.h"
|
||||
|
||||
#include "math/matrix4.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class Framebuffer;
|
||||
|
||||
/**
|
||||
* Interface for OpenGL pipeline functionality.
|
||||
*
|
||||
* This encapsulates differences in various rendering pipelines used for
|
||||
* OpenGL, OpenGL ES 1, and OpenGL ES 2.
|
||||
*/
|
||||
class Pipeline {
|
||||
public:
|
||||
/**
|
||||
* Deactivate any pipeline.
|
||||
*/
|
||||
static void disable() { if (activePipeline) activePipeline->deactivate(); }
|
||||
|
||||
Pipeline();
|
||||
virtual ~Pipeline() { if (isActive()) deactivate(); }
|
||||
|
||||
/**
|
||||
* Activate the pipeline.
|
||||
*
|
||||
* This sets the OpenGL state to make use of drawing with the given
|
||||
* OpenGL pipeline.
|
||||
*/
|
||||
void activate();
|
||||
|
||||
/**
|
||||
* Deactivate the pipeline.
|
||||
*/
|
||||
void deactivate();
|
||||
|
||||
/**
|
||||
* Set framebuffer to render to.
|
||||
*
|
||||
* Client is responsible for any memory management related to framebuffer.
|
||||
*
|
||||
* @param framebuffer Framebuffer to activate.
|
||||
* @return Formerly active framebuffer.
|
||||
*/
|
||||
Framebuffer *setFramebuffer(Framebuffer *framebuffer);
|
||||
|
||||
/**
|
||||
* Set modulation color.
|
||||
*
|
||||
* @param r Red component in [0,1].
|
||||
* @param g Green component in [0,1].
|
||||
* @param b Blue component in [0,1].
|
||||
* @param a Alpha component in [0,1].
|
||||
*/
|
||||
virtual void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) = 0;
|
||||
|
||||
/**
|
||||
* Draw a texture rectangle to the currently active framebuffer.
|
||||
*
|
||||
* @param texture Texture to use for drawing.
|
||||
* @param coordinates x1, y1, x2, y2 coordinates where to draw the texture.
|
||||
*/
|
||||
inline void drawTexture(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) {
|
||||
drawTextureInternal(texture, coordinates, texcoords);
|
||||
}
|
||||
|
||||
inline void drawTexture(const Texture &texture, const GLfloat *coordinates) {
|
||||
drawTextureInternal(texture, coordinates, texture.getTexCoords());
|
||||
}
|
||||
|
||||
inline void drawTexture(const Texture &texture, GLfloat x, GLfloat y, GLfloat w, GLfloat h) {
|
||||
const GLfloat coordinates[4*2] = {
|
||||
x, y,
|
||||
x + w, y,
|
||||
x, y + h,
|
||||
x + w, y + h
|
||||
};
|
||||
drawTextureInternal(texture, coordinates, texture.getTexCoords());
|
||||
}
|
||||
|
||||
inline void drawTexture(const Texture &texture, GLfloat x, GLfloat y, GLfloat w, GLfloat h, const Common::Rect &clip) {
|
||||
const GLfloat coordinates[4*2] = {
|
||||
x, y,
|
||||
x + w, y,
|
||||
x, y + h,
|
||||
x + w, y + h
|
||||
};
|
||||
|
||||
const uint tw = texture.getWidth(),
|
||||
th = texture.getHeight();
|
||||
|
||||
if (tw == 0 || th == 0) {
|
||||
// Nothing to display
|
||||
return;
|
||||
}
|
||||
|
||||
const GLfloat texcoords[4*2] = {
|
||||
(float)clip.left / tw, (float)clip.top / th,
|
||||
(float)clip.right / tw, (float)clip.top / th,
|
||||
(float)clip.left / tw, (float)clip.bottom / th,
|
||||
(float)clip.right / tw, (float)clip.bottom / th
|
||||
};
|
||||
|
||||
drawTextureInternal(texture, coordinates, texcoords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the projection matrix.
|
||||
*
|
||||
* This is intended to be only ever be used by Framebuffer subclasses.
|
||||
*/
|
||||
virtual void setProjectionMatrix(const Math::Matrix4 &projectionMatrix) = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Activate the pipeline.
|
||||
*
|
||||
* This sets the OpenGL state to make use of drawing with the given
|
||||
* OpenGL pipeline.
|
||||
*/
|
||||
virtual void activateInternal();
|
||||
|
||||
/**
|
||||
* Deactivate the pipeline.
|
||||
*/
|
||||
virtual void deactivateInternal();
|
||||
|
||||
virtual void drawTextureInternal(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) = 0;
|
||||
|
||||
bool isActive() const { return activePipeline == this; }
|
||||
|
||||
Framebuffer *_activeFramebuffer;
|
||||
|
||||
private:
|
||||
/** Currently active rendering pipeline. */
|
||||
static Pipeline *activePipeline;
|
||||
};
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
110
backends/graphics/opengl/pipelines/shader.cpp
Normal file
110
backends/graphics/opengl/pipelines/shader.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/* 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 "backends/graphics/opengl/pipelines/shader.h"
|
||||
#include "backends/graphics/opengl/shader.h"
|
||||
#include "backends/graphics/opengl/framebuffer.h"
|
||||
#include "graphics/opengl/debug.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
// A 4 elements with 2 components vector of floats
|
||||
static const int kCoordinatesSize = 4 * 2 * sizeof(float);
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
ShaderPipeline::ShaderPipeline(Shader *shader)
|
||||
: _activeShader(shader), _colorAttributes(), _colorDirty(true) {
|
||||
// Use the same VBO for vertices and texcoords as we modify them at the same time
|
||||
_coordsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, kCoordinatesSize, nullptr, GL_STATIC_DRAW);
|
||||
_activeShader->enableVertexAttribute("position", _coordsVBO, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
_texcoordsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, kCoordinatesSize, nullptr, GL_STATIC_DRAW);
|
||||
_activeShader->enableVertexAttribute("texCoordIn", _texcoordsVBO, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
_colorVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(_colorAttributes), nullptr, GL_DYNAMIC_DRAW);
|
||||
_activeShader->enableVertexAttribute("blendColorIn", _colorVBO, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
ShaderPipeline::~ShaderPipeline() {
|
||||
delete _activeShader;
|
||||
|
||||
OpenGL::Shader::freeBuffer(_coordsVBO);
|
||||
OpenGL::Shader::freeBuffer(_texcoordsVBO);
|
||||
OpenGL::Shader::freeBuffer(_colorVBO);
|
||||
}
|
||||
|
||||
void ShaderPipeline::activateInternal() {
|
||||
Pipeline::activateInternal();
|
||||
|
||||
// Disable 3D properties.
|
||||
GL_CALL(glDisable(GL_CULL_FACE));
|
||||
GL_CALL(glDisable(GL_DEPTH_TEST));
|
||||
GL_CALL(glDisable(GL_DITHER));
|
||||
|
||||
if (OpenGLContext.multitextureSupported) {
|
||||
GL_CALL(glActiveTexture(GL_TEXTURE0));
|
||||
}
|
||||
|
||||
_activeShader->use();
|
||||
}
|
||||
|
||||
void ShaderPipeline::deactivateInternal() {
|
||||
_activeShader->unbind();
|
||||
|
||||
Pipeline::deactivateInternal();
|
||||
}
|
||||
|
||||
void ShaderPipeline::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
|
||||
GLfloat *dst = _colorAttributes;
|
||||
for (uint i = 0; i < 4; ++i) {
|
||||
*dst++ = r;
|
||||
*dst++ = g;
|
||||
*dst++ = b;
|
||||
*dst++ = a;
|
||||
}
|
||||
_colorDirty = true;
|
||||
}
|
||||
|
||||
void ShaderPipeline::drawTextureInternal(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) {
|
||||
assert(isActive());
|
||||
|
||||
texture.bind();
|
||||
|
||||
if (_colorDirty) {
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, _colorVBO));
|
||||
GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_colorAttributes), _colorAttributes));
|
||||
_colorDirty = false;
|
||||
}
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, _coordsVBO));
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, kCoordinatesSize, coordinates, GL_STATIC_DRAW));
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, _texcoordsVBO));
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, kCoordinatesSize, texcoords, GL_STATIC_DRAW));
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
|
||||
GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
|
||||
}
|
||||
|
||||
void ShaderPipeline::setProjectionMatrix(const Math::Matrix4 &projectionMatrix) {
|
||||
assert(isActive());
|
||||
|
||||
_activeShader->setUniform("projection", projectionMatrix);
|
||||
}
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
} // End of namespace OpenGL
|
||||
59
backends/graphics/opengl/pipelines/shader.h
Normal file
59
backends/graphics/opengl/pipelines/shader.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_PIPELINES_SHADER_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_SHADER_H
|
||||
|
||||
#include "backends/graphics/opengl/pipelines/pipeline.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
class Shader;
|
||||
|
||||
class ShaderPipeline : public Pipeline {
|
||||
public:
|
||||
ShaderPipeline(Shader *shader);
|
||||
~ShaderPipeline() override;
|
||||
|
||||
void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) override;
|
||||
|
||||
void setProjectionMatrix(const Math::Matrix4 &projectionMatrix) override;
|
||||
|
||||
protected:
|
||||
void activateInternal() override;
|
||||
void deactivateInternal() override;
|
||||
void drawTextureInternal(const Texture &texture, const GLfloat *coordinates, const GLfloat *texcoords) override;
|
||||
|
||||
GLuint _coordsVBO;
|
||||
GLuint _texcoordsVBO;
|
||||
GLuint _colorVBO;
|
||||
|
||||
GLfloat _colorAttributes[4*4];
|
||||
bool _colorDirty;
|
||||
|
||||
Shader *const _activeShader;
|
||||
};
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
484
backends/graphics/opengl/renderer3d.cpp
Normal file
484
backends/graphics/opengl/renderer3d.cpp
Normal file
@@ -0,0 +1,484 @@
|
||||
/* 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/scummsys.h"
|
||||
|
||||
#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
|
||||
|
||||
#include "backends/graphics/opengl/renderer3d.h"
|
||||
#include "backends/graphics/opengl/pipelines/pipeline.h"
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
static void setupRenderbufferStorage(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
#if !USE_FORCED_GLES2 || defined(USE_GLAD)
|
||||
if (samples > 1) {
|
||||
glRenderbufferStorageMultisample(target, samples, internalformat, width, height);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
glRenderbufferStorage(target, internalformat, width, height);
|
||||
}
|
||||
|
||||
// This constructor must not depend on any existing GL context
|
||||
Renderer3D::Renderer3D() :
|
||||
_texture(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, false),
|
||||
_renderBuffers{0, 0, 0}, _frameBuffers{0, 0}, _renderToFrameBuffer(false),
|
||||
_samples(0), _stackLevel(0), _inOverlay(false),
|
||||
_pendingScreenChangeWidth(-1), _pendingScreenChangeHeight(-1) {
|
||||
_texture.enableLinearFiltering(true);
|
||||
_texture.setFlip(true);
|
||||
}
|
||||
|
||||
void Renderer3D::destroy() {
|
||||
while (_stackLevel) {
|
||||
enter3D();
|
||||
}
|
||||
|
||||
if (_frameBuffers[0]) {
|
||||
// Check that we did allocated some framebuffer before destroying them
|
||||
// This avoids to call glDeleteFramebuffers and glDeleteRenderbuffers
|
||||
// on platforms not supporting it
|
||||
glDeleteFramebuffers(ARRAYSIZE(_frameBuffers), _frameBuffers);
|
||||
glDeleteRenderbuffers(ARRAYSIZE(_renderBuffers), _renderBuffers);
|
||||
memset(_renderBuffers, 0, sizeof(_renderBuffers));
|
||||
memset(_frameBuffers, 0, sizeof(_frameBuffers));
|
||||
}
|
||||
|
||||
_texture.destroy();
|
||||
}
|
||||
|
||||
void Renderer3D::initSize(uint w, uint h, int samples, bool renderToFrameBuffer) {
|
||||
_samples = samples;
|
||||
_renderToFrameBuffer = renderToFrameBuffer;
|
||||
|
||||
if (!renderToFrameBuffer) {
|
||||
destroy();
|
||||
_texture.setSize(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_texture.setSize(w, h);
|
||||
recreate();
|
||||
}
|
||||
|
||||
void Renderer3D::resize(uint w, uint h) {
|
||||
assert(!_stackLevel);
|
||||
|
||||
if (!_renderToFrameBuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_inOverlay) {
|
||||
// While the (GUI) overlay is active, the game doesn't renders
|
||||
// So, instead of loosing the contents of the FBO because of a resize,
|
||||
// just delay it to when we close the GUI.
|
||||
_pendingScreenChangeWidth = w;
|
||||
_pendingScreenChangeHeight = h;
|
||||
return;
|
||||
}
|
||||
|
||||
_texture.setSize(w, h);
|
||||
setup();
|
||||
|
||||
// Rebind the framebuffer
|
||||
#if !USE_FORCED_GLES2 || defined(USE_GLAD)
|
||||
if (_frameBuffers[1]) {
|
||||
// We are using multisampling
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, _frameBuffers[1]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _frameBuffers[0]);
|
||||
} else if (_frameBuffers[0])
|
||||
#endif
|
||||
{
|
||||
// Draw on framebuffer if one was setup
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffers[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer3D::recreate() {
|
||||
destroy();
|
||||
|
||||
if (!_renderToFrameBuffer) {
|
||||
// No framebuffer was requested
|
||||
return;
|
||||
}
|
||||
|
||||
// A 1x antialiasing is not an antialiasing
|
||||
if (_samples > 1) {
|
||||
#if !USE_FORCED_GLES2 || defined(USE_GLAD)
|
||||
if (!OpenGLContext.framebufferObjectMultisampleSupported) {
|
||||
warning("The current OpenGL context does not support multisample framebuffer objects");
|
||||
_samples = 0;
|
||||
}
|
||||
if (_samples > OpenGLContext.multisampleMaxSamples) {
|
||||
warning("Requested anti-aliasing with '%d' samples, but the current OpenGL context supports '%d' samples at most",
|
||||
_samples, OpenGLContext.multisampleMaxSamples);
|
||||
_samples = OpenGLContext.multisampleMaxSamples;
|
||||
}
|
||||
#else
|
||||
warning("multisample framebuffer objects support is not compiled in");
|
||||
_samples = 0;
|
||||
#endif
|
||||
} else {
|
||||
_samples = 0;
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
// Context got destroyed
|
||||
_stackLevel = 0;
|
||||
}
|
||||
|
||||
void Renderer3D::setup() {
|
||||
#if !USE_FORCED_GLES2 || defined(USE_GLAD)
|
||||
const bool multiSample = _samples > 1;
|
||||
#else
|
||||
const bool multiSample = false;
|
||||
#endif
|
||||
const uint w = _texture.getLogicalWidth();
|
||||
const uint h = _texture.getLogicalHeight();
|
||||
|
||||
if (!_texture.getGLTexture()) {
|
||||
_texture.create();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (!_frameBuffers[0]) {
|
||||
glGenFramebuffers(multiSample ? 2 : 1, _frameBuffers);
|
||||
glGenRenderbuffers(multiSample ? 3 : 2, _renderBuffers);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffers[multiSample ? 1 : 0]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture.getGLTexture(), 0);
|
||||
|
||||
#if !USE_FORCED_GLES2 || defined(USE_GLAD)
|
||||
if (multiSample) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffers[0]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[2]);
|
||||
setupRenderbufferStorage(GL_RENDERBUFFER, _samples, GL_RGBA8, w, h);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderBuffers[2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
// See https://www.khronos.org/registry/webgl/specs/latest/1.0/#FBO_ATTACHMENTS
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]);
|
||||
setupRenderbufferStorage(GL_RENDERBUFFER, _samples, GL_DEPTH_STENCIL, w, h);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
|
||||
#else
|
||||
if (OpenGLContext.packedDepthStencilSupported) {
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]);
|
||||
setupRenderbufferStorage(GL_RENDERBUFFER, _samples, GL_DEPTH24_STENCIL8, w, h);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
|
||||
} else {
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[0]);
|
||||
setupRenderbufferStorage(GL_RENDERBUFFER, _samples, OpenGLContext.OESDepth24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, w, h);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[0]);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffers[1]);
|
||||
setupRenderbufferStorage(GL_RENDERBUFFER, _samples, GL_STENCIL_INDEX8, w, h);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderBuffers[1]);
|
||||
}
|
||||
#endif
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
error("Framebuffer is not complete! status: %d", status);
|
||||
}
|
||||
|
||||
if (multiSample) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffers[1]);
|
||||
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
error("Target framebuffer is not complete! status: %d", status);
|
||||
}
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void Renderer3D::leave3D() {
|
||||
#if !USE_FORCED_GLES2
|
||||
if (OpenGLContext.type == kContextGL) {
|
||||
// Save current state (only available on OpenGL)
|
||||
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT |
|
||||
GL_LIGHTING_BIT | GL_PIXEL_MODE_BIT | GL_SCISSOR_BIT |
|
||||
GL_TEXTURE_BIT | GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);
|
||||
glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT | GL_CLIENT_VERTEX_ARRAY_BIT);
|
||||
|
||||
// prepare view
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPushMatrix();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// Save context by ourselves
|
||||
#define CTX_STATE(gl_param) _save ## gl_param = glIsEnabled(gl_param)
|
||||
#define CTX_BOOLEAN(gl_param) glGetBooleanv(gl_param, &_save ## gl_param)
|
||||
#define CTX_INTEGER(gl_param, count) glGetIntegerv(gl_param, _save ## gl_param)
|
||||
|
||||
CTX_STATE(GL_BLEND);
|
||||
CTX_STATE(GL_CULL_FACE);
|
||||
CTX_STATE(GL_DEPTH_TEST);
|
||||
CTX_STATE(GL_DITHER);
|
||||
CTX_STATE(GL_POLYGON_OFFSET_FILL);
|
||||
CTX_STATE(GL_SCISSOR_TEST);
|
||||
CTX_STATE(GL_STENCIL_TEST);
|
||||
|
||||
CTX_BOOLEAN(GL_DEPTH_WRITEMASK);
|
||||
|
||||
CTX_INTEGER(GL_BLEND_SRC_RGB, 1);
|
||||
CTX_INTEGER(GL_BLEND_DST_RGB, 1);
|
||||
CTX_INTEGER(GL_BLEND_SRC_ALPHA, 1);
|
||||
CTX_INTEGER(GL_BLEND_DST_ALPHA, 1);
|
||||
|
||||
CTX_INTEGER(GL_SCISSOR_BOX, 4);
|
||||
CTX_INTEGER(GL_VIEWPORT, 4);
|
||||
|
||||
#undef CTX_INTEGER
|
||||
#undef CTX_BOOLEAN
|
||||
#undef CTX_STATE
|
||||
}
|
||||
_stackLevel++;
|
||||
|
||||
#if !USE_FORCED_GLES2 || defined(USE_GLAD)
|
||||
if (_frameBuffers[1]) {
|
||||
// Frambuffer blit is impacted by scissor test, disable it
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
// We are using multisampling
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, _frameBuffers[0]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _frameBuffers[1]);
|
||||
const uint w = _texture.getLogicalWidth();
|
||||
const uint h = _texture.getLogicalHeight();
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
} else if (_frameBuffers[0])
|
||||
#endif
|
||||
{
|
||||
// Don't mess with the framebuffer if one was setup
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer3D::enter3D() {
|
||||
#if !USE_FORCED_GLES2 || defined(USE_GLAD)
|
||||
if (_frameBuffers[1]) {
|
||||
// We are using multisampling
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, _frameBuffers[1]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _frameBuffers[0]);
|
||||
} else if (_frameBuffers[0])
|
||||
#endif
|
||||
{
|
||||
// Draw on framebuffer if one was setup
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffers[0]);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
Pipeline::disable();
|
||||
|
||||
if (_stackLevel) {
|
||||
#if !USE_FORCED_GLES2
|
||||
if (OpenGLContext.type == kContextGL) {
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glPopClientAttrib();
|
||||
glPopAttrib();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#define CTX_STATE(gl_param) _save ## gl_param ? glEnable(gl_param) : glDisable(gl_param)
|
||||
|
||||
CTX_STATE(GL_BLEND);
|
||||
CTX_STATE(GL_CULL_FACE);
|
||||
CTX_STATE(GL_DEPTH_TEST);
|
||||
CTX_STATE(GL_DITHER);
|
||||
CTX_STATE(GL_POLYGON_OFFSET_FILL);
|
||||
CTX_STATE(GL_SCISSOR_TEST);
|
||||
CTX_STATE(GL_STENCIL_TEST);
|
||||
|
||||
glDepthMask(_saveGL_DEPTH_WRITEMASK);
|
||||
|
||||
glBlendFuncSeparate(_saveGL_BLEND_SRC_RGB[0], _saveGL_BLEND_DST_RGB[0],
|
||||
_saveGL_BLEND_SRC_ALPHA[0], _saveGL_BLEND_DST_ALPHA[0]);
|
||||
|
||||
glScissor(_saveGL_SCISSOR_BOX[0], _saveGL_SCISSOR_BOX[1],
|
||||
_saveGL_SCISSOR_BOX[2], _saveGL_SCISSOR_BOX[3]);
|
||||
|
||||
glViewport(_saveGL_VIEWPORT[0], _saveGL_VIEWPORT[1],
|
||||
_saveGL_VIEWPORT[2], _saveGL_VIEWPORT[3]);
|
||||
#undef CTX_STATE
|
||||
}
|
||||
_stackLevel--;
|
||||
} else {
|
||||
// 3D engine just starts, make sure the state is clean
|
||||
glDisable(GL_BLEND);
|
||||
if (OpenGLContext.imagingSupported) {
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
}
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
glEnable(GL_DITHER);
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(0.f, 0.f);
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glScissor(0, 0, g_system->getWidth(), g_system->getHeight());
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glStencilFunc(GL_ALWAYS, 0, -1u);
|
||||
glStencilMask(-1u);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glLineWidth(1.f);
|
||||
|
||||
glViewport(0, 0, g_system->getWidth(), g_system->getHeight());
|
||||
|
||||
#if !USE_FORCED_GLES2
|
||||
if (OpenGLContext.type == kContextGL) {
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_ALWAYS, 0);
|
||||
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
||||
|
||||
glDisable(GL_FOG);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
glDisable(GL_NORMALIZE);
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glDisable(GL_POLYGON_STIPPLE);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_TEXTURE_3D);
|
||||
glDisable(GL_TEXTURE_CUBE_MAP);
|
||||
glDisable(GL_TEXTURE_GEN_Q);
|
||||
glDisable(GL_TEXTURE_GEN_R);
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_EDGE_FLAG_ARRAY);
|
||||
glDisableClientState(GL_FOG_COORD_ARRAY);
|
||||
glDisableClientState(GL_INDEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
// The others targets are not modified by engines
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
|
||||
glLogicOp(GL_COPY);
|
||||
glPointSize(1.f);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer3D::presentBuffer() {
|
||||
#if !USE_FORCED_GLES2 || defined(USE_GLAD)
|
||||
if (!_frameBuffers[1]) {
|
||||
// We are not using multisampling: contents are readily available
|
||||
// The engine just has to read from the FBO or the backbuffer
|
||||
return;
|
||||
}
|
||||
|
||||
assert(_stackLevel == 0);
|
||||
bool saveScissorTest = glIsEnabled(GL_SCISSOR_TEST);
|
||||
|
||||
// Frambuffer blit is impacted by scissor test, disable it
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
// Swap the framebuffers and blit
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, _frameBuffers[0]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _frameBuffers[1]);
|
||||
const uint w = _texture.getLogicalWidth();
|
||||
const uint h = _texture.getLogicalHeight();
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
// Put back things as they were before
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, _frameBuffers[1]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _frameBuffers[0]);
|
||||
|
||||
saveScissorTest ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Renderer3D::showOverlay(uint w, uint h) {
|
||||
_inOverlay = true;
|
||||
|
||||
if (_frameBuffers[0]) {
|
||||
// We have a framebuffer: the texture already contains an image
|
||||
return;
|
||||
}
|
||||
|
||||
_texture.create();
|
||||
_texture.setSize(w, h);
|
||||
Graphics::Surface background;
|
||||
background.create(w, h, Texture::getRGBAPixelFormat());
|
||||
glReadPixels(0, 0, background.w, background.h, GL_RGBA, GL_UNSIGNED_BYTE, background.getPixels());
|
||||
_texture.updateArea(Common::Rect(w, h), background);
|
||||
background.free();
|
||||
}
|
||||
|
||||
void Renderer3D::hideOverlay() {
|
||||
_inOverlay = false;
|
||||
|
||||
if (!_frameBuffers[0]) {
|
||||
// We don't have a framebuffer: destroy the texture we used to store the background
|
||||
_texture.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// We have a framebuffer: resize the screen if we have a pending change
|
||||
if (_pendingScreenChangeWidth >= 0 && _pendingScreenChangeHeight >= 0) {
|
||||
resize(_pendingScreenChangeWidth, _pendingScreenChangeHeight);
|
||||
_pendingScreenChangeWidth = -1;
|
||||
_pendingScreenChangeHeight = -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
99
backends/graphics/opengl/renderer3d.h
Normal file
99
backends/graphics/opengl/renderer3d.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_RENDERER3D_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_RENDERER3D_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
|
||||
|
||||
#include "graphics/opengl/texture.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class Renderer3D {
|
||||
public:
|
||||
Renderer3D();
|
||||
~Renderer3D() { destroy(); }
|
||||
|
||||
void initSize(uint w, uint h, int samples, bool renderToFrameBuffer);
|
||||
void resize(uint w, uint h);
|
||||
void recreate();
|
||||
void destroy();
|
||||
|
||||
void leave3D();
|
||||
void enter3D();
|
||||
void presentBuffer();
|
||||
|
||||
void showOverlay(uint w, uint h);
|
||||
void hideOverlay();
|
||||
|
||||
const Texture &getGLTexture() const { return _texture; }
|
||||
bool hasTexture() const { return _texture.getGLTexture() != 0; }
|
||||
|
||||
void setRotation(Common::RotationMode rotation) { _texture.setRotation(rotation); }
|
||||
|
||||
protected:
|
||||
void setup();
|
||||
|
||||
int _stackLevel;
|
||||
bool _inOverlay;
|
||||
int _pendingScreenChangeWidth;
|
||||
int _pendingScreenChangeHeight;
|
||||
|
||||
bool _renderToFrameBuffer;
|
||||
int _samples;
|
||||
Texture _texture;
|
||||
GLuint _renderBuffers[3];
|
||||
GLuint _frameBuffers[2];
|
||||
|
||||
#define CTX_STATE(gl_param) GLboolean _save ## gl_param = false
|
||||
#define CTX_BOOLEAN(gl_param) GLboolean _save ## gl_param = false
|
||||
#define CTX_INTEGER(gl_param, count) GLint _save ## gl_param[count] = { 0 }
|
||||
|
||||
CTX_STATE(GL_BLEND);
|
||||
CTX_STATE(GL_CULL_FACE);
|
||||
CTX_STATE(GL_DEPTH_TEST);
|
||||
CTX_STATE(GL_DITHER);
|
||||
CTX_STATE(GL_POLYGON_OFFSET_FILL);
|
||||
CTX_STATE(GL_SCISSOR_TEST);
|
||||
CTX_STATE(GL_STENCIL_TEST);
|
||||
|
||||
CTX_BOOLEAN(GL_DEPTH_WRITEMASK);
|
||||
|
||||
CTX_INTEGER(GL_BLEND_SRC_RGB, 1);
|
||||
CTX_INTEGER(GL_BLEND_DST_RGB, 1);
|
||||
CTX_INTEGER(GL_BLEND_SRC_ALPHA, 1);
|
||||
CTX_INTEGER(GL_BLEND_DST_ALPHA, 1);
|
||||
CTX_INTEGER(GL_SCISSOR_BOX, 4);
|
||||
CTX_INTEGER(GL_VIEWPORT, 4);
|
||||
|
||||
#undef CTX_INTEGER
|
||||
#undef CTX_BOOLEAN
|
||||
#undef CTX_STATE
|
||||
};
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif // defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
|
||||
|
||||
#endif
|
||||
128
backends/graphics/opengl/shader.cpp
Normal file
128
backends/graphics/opengl/shader.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 "backends/graphics/opengl/shader.h"
|
||||
#include "graphics/opengl/debug.h"
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(OpenGL::ShaderManager);
|
||||
}
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
namespace {
|
||||
|
||||
#pragma mark - Builtin Shader Sources -
|
||||
|
||||
const char *const g_defaultShaderAttributes[] = {
|
||||
"position", "texCoordIn", "blendColorIn", nullptr
|
||||
};
|
||||
|
||||
const char *const g_defaultVertexShader =
|
||||
"attribute vec4 position;\n"
|
||||
"attribute vec2 texCoordIn;\n"
|
||||
"attribute vec4 blendColorIn;\n"
|
||||
"\n"
|
||||
"uniform mat4 projection;\n"
|
||||
"\n"
|
||||
"varying vec2 texCoord;\n"
|
||||
"varying vec4 blendColor;\n"
|
||||
"\n"
|
||||
"void main(void) {\n"
|
||||
"\ttexCoord = texCoordIn;\n"
|
||||
"\tblendColor = blendColorIn;\n"
|
||||
"\tgl_Position = projection * position;\n"
|
||||
"}\n";
|
||||
|
||||
const char *const g_defaultFragmentShader =
|
||||
"varying vec2 texCoord;\n"
|
||||
"varying vec4 blendColor;\n"
|
||||
"\n"
|
||||
"uniform sampler2D shaderTexture;\n"
|
||||
"\n"
|
||||
"void main(void) {\n"
|
||||
"\tgl_FragColor = blendColor * texture2D(shaderTexture, texCoord);\n"
|
||||
"}\n";
|
||||
|
||||
const char *const g_lookUpFragmentShader =
|
||||
"varying vec2 texCoord;\n"
|
||||
"varying vec4 blendColor;\n"
|
||||
"\n"
|
||||
"uniform sampler2D shaderTexture;\n"
|
||||
"uniform sampler2D palette;\n"
|
||||
"\n"
|
||||
"const float scaleFactor = 255.0 / 256.0;\n"
|
||||
"const float offsetFactor = 1.0 / (2.0 * 256.0);\n"
|
||||
"\n"
|
||||
"void main(void) {\n"
|
||||
"\tvec4 index = texture2D(shaderTexture, texCoord);\n"
|
||||
"\tgl_FragColor = blendColor * texture2D(palette, vec2(index.a * scaleFactor + offsetFactor, 0.0));\n"
|
||||
"}\n";
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
||||
ShaderManager::ShaderManager() {
|
||||
for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
|
||||
_builtIn[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderManager::~ShaderManager() {
|
||||
for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
|
||||
delete _builtIn[i];
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderManager::notifyDestroy() {
|
||||
for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
|
||||
delete _builtIn[i];
|
||||
_builtIn[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderManager::notifyCreate() {
|
||||
// Ensure everything is destroyed
|
||||
notifyDestroy();
|
||||
|
||||
_builtIn[kDefault] = Shader::fromStrings("default", g_defaultVertexShader, g_defaultFragmentShader, g_defaultShaderAttributes, 110);
|
||||
_builtIn[kCLUT8LookUp] = Shader::fromStrings("clut8lookup", g_defaultVertexShader, g_lookUpFragmentShader, g_defaultShaderAttributes, 110);
|
||||
_builtIn[kCLUT8LookUp]->setUniform("palette", 1);
|
||||
|
||||
for (uint i = 0; i < kMaxUsages; ++i) {
|
||||
_builtIn[i]->setUniform("shaderTexture", 0);
|
||||
}
|
||||
}
|
||||
|
||||
Shader *ShaderManager::query(ShaderUsage shader) const {
|
||||
if (shader == kMaxUsages) {
|
||||
warning("OpenGL: ShaderManager::query used with kMaxUsages");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(_builtIn[shader]);
|
||||
return _builtIn[shader]->clone();
|
||||
}
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif // !USE_FORCED_GLES
|
||||
79
backends/graphics/opengl/shader.h
Normal file
79
backends/graphics/opengl/shader.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_SHADER_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_SHADER_H
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
|
||||
#include "common/singleton.h"
|
||||
|
||||
#include "graphics/opengl/shader.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class ShaderManager : public Common::Singleton<ShaderManager> {
|
||||
public:
|
||||
enum ShaderUsage {
|
||||
/** Default shader implementing the GL fixed-function pipeline. */
|
||||
kDefault = 0,
|
||||
|
||||
/** CLUT8 look up shader. */
|
||||
kCLUT8LookUp,
|
||||
|
||||
/** Number of built-in shaders. Should not be used for query. */
|
||||
kMaxUsages
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify shader manager about context destruction.
|
||||
*/
|
||||
void notifyDestroy();
|
||||
|
||||
/**
|
||||
* Notify shader manager about context creation.
|
||||
*/
|
||||
void notifyCreate();
|
||||
|
||||
/**
|
||||
* Query a built-in shader.
|
||||
* Shader returned must be destroyed by caller.
|
||||
*/
|
||||
Shader *query(ShaderUsage shader) const;
|
||||
|
||||
private:
|
||||
friend class Common::Singleton<SingletonBaseType>;
|
||||
ShaderManager();
|
||||
~ShaderManager();
|
||||
|
||||
Shader *_builtIn[kMaxUsages];
|
||||
};
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
/** Shortcut for accessing the font manager. */
|
||||
#define ShaderMan (OpenGL::ShaderManager::instance())
|
||||
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
#endif
|
||||
652
backends/graphics/opengl/texture.cpp
Normal file
652
backends/graphics/opengl/texture.cpp
Normal file
@@ -0,0 +1,652 @@
|
||||
/* 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 "backends/graphics/opengl/texture.h"
|
||||
#include "backends/graphics/opengl/shader.h"
|
||||
#include "backends/graphics/opengl/pipelines/pipeline.h"
|
||||
#include "backends/graphics/opengl/pipelines/clut8.h"
|
||||
#include "backends/graphics/opengl/framebuffer.h"
|
||||
#include "graphics/opengl/debug.h"
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "graphics/blit.h"
|
||||
|
||||
#ifdef USE_SCALERS
|
||||
#include "graphics/scalerplugin.h"
|
||||
#endif
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
//
|
||||
// Surface
|
||||
//
|
||||
|
||||
Surface::Surface()
|
||||
: _allDirty(false), _dirtyArea() {
|
||||
}
|
||||
|
||||
void Surface::copyRectToTexture(uint x, uint y, uint w, uint h, const void *srcPtr, uint srcPitch) {
|
||||
Graphics::Surface *dstSurf = getSurface();
|
||||
assert(x + w <= (uint)dstSurf->w);
|
||||
assert(y + h <= (uint)dstSurf->h);
|
||||
|
||||
addDirtyArea(Common::Rect(x, y, x + w, y + h));
|
||||
|
||||
const byte *src = (const byte *)srcPtr;
|
||||
byte *dst = (byte *)dstSurf->getBasePtr(x, y);
|
||||
const uint pitch = dstSurf->pitch;
|
||||
const uint bytesPerPixel = dstSurf->format.bytesPerPixel;
|
||||
|
||||
if (srcPitch == pitch && x == 0 && w == (uint)dstSurf->w) {
|
||||
memcpy(dst, src, h * pitch);
|
||||
} else {
|
||||
while (h-- > 0) {
|
||||
memcpy(dst, src, w * bytesPerPixel);
|
||||
dst += pitch;
|
||||
src += srcPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::fill(uint32 color) {
|
||||
Graphics::Surface *dst = getSurface();
|
||||
dst->fillRect(Common::Rect(dst->w, dst->h), color);
|
||||
|
||||
flagDirty();
|
||||
}
|
||||
|
||||
void Surface::fill(const Common::Rect &r, uint32 color) {
|
||||
Graphics::Surface *dst = getSurface();
|
||||
dst->fillRect(r, color);
|
||||
|
||||
addDirtyArea(r);
|
||||
}
|
||||
|
||||
void Surface::addDirtyArea(const Common::Rect &r) {
|
||||
// *sigh* Common::Rect::extend behaves unexpected whenever one of the two
|
||||
// parameters is an empty rect. Thus, we check whether the current dirty
|
||||
// area is valid. In case it is not we simply use the parameters as new
|
||||
// dirty area. Otherwise, we simply call extend.
|
||||
if (_dirtyArea.isEmpty()) {
|
||||
_dirtyArea = r;
|
||||
} else {
|
||||
_dirtyArea.extend(r);
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect Surface::getDirtyArea() const {
|
||||
if (_allDirty) {
|
||||
return Common::Rect(getWidth(), getHeight());
|
||||
} else {
|
||||
return _dirtyArea;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Surface implementations
|
||||
//
|
||||
|
||||
TextureSurface::TextureSurface(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format)
|
||||
: Surface(), _format(format), _glTexture(glIntFormat, glFormat, glType),
|
||||
_textureData(), _userPixelData() {
|
||||
}
|
||||
|
||||
TextureSurface::~TextureSurface() {
|
||||
_textureData.free();
|
||||
}
|
||||
|
||||
void TextureSurface::destroy() {
|
||||
_glTexture.destroy();
|
||||
}
|
||||
|
||||
void TextureSurface::recreate() {
|
||||
_glTexture.create();
|
||||
|
||||
// In case image date exists assure it will be completely refreshed next
|
||||
// time.
|
||||
if (_textureData.getPixels()) {
|
||||
flagDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSurface::enableLinearFiltering(bool enable) {
|
||||
_glTexture.enableLinearFiltering(enable);
|
||||
}
|
||||
|
||||
void TextureSurface::setRotation(Common::RotationMode rotation) {
|
||||
_glTexture.setRotation(rotation);
|
||||
}
|
||||
|
||||
void TextureSurface::allocate(uint width, uint height) {
|
||||
// Assure the texture can contain our user data.
|
||||
_glTexture.setSize(width, height);
|
||||
|
||||
// In case the needed texture dimension changed we will reinitialize the
|
||||
// texture data buffer.
|
||||
if (_glTexture.getWidth() != (uint)_textureData.w || _glTexture.getHeight() != (uint)_textureData.h) {
|
||||
// Create a buffer for the texture data.
|
||||
_textureData.create(_glTexture.getWidth(), _glTexture.getHeight(), _format);
|
||||
}
|
||||
|
||||
// Create a sub-buffer for raw access.
|
||||
_userPixelData = _textureData.getSubArea(Common::Rect(width, height));
|
||||
|
||||
// The whole texture is dirty after we changed the size. This fixes
|
||||
// multiple texture size changes without any actual update in between.
|
||||
// Without this we might try to write a too big texture into the GL
|
||||
// texture.
|
||||
flagDirty();
|
||||
}
|
||||
|
||||
void TextureSurface::updateGLTexture() {
|
||||
if (!isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Rect dirtyArea = getDirtyArea();
|
||||
|
||||
updateGLTexture(dirtyArea);
|
||||
}
|
||||
|
||||
void TextureSurface::updateGLTexture(Common::Rect &dirtyArea) {
|
||||
// In case we use linear filtering we might need to duplicate the last
|
||||
// pixel row/column to avoid glitches with filtering.
|
||||
if (_glTexture.isLinearFilteringEnabled()) {
|
||||
if (dirtyArea.right == _userPixelData.w && _userPixelData.w != _textureData.w) {
|
||||
uint height = dirtyArea.height();
|
||||
|
||||
const byte *src = (const byte *)_textureData.getBasePtr(_userPixelData.w - 1, dirtyArea.top);
|
||||
byte *dst = (byte *)_textureData.getBasePtr(_userPixelData.w, dirtyArea.top);
|
||||
|
||||
while (height-- > 0) {
|
||||
memcpy(dst, src, _textureData.format.bytesPerPixel);
|
||||
dst += _textureData.pitch;
|
||||
src += _textureData.pitch;
|
||||
}
|
||||
|
||||
// Extend the dirty area.
|
||||
++dirtyArea.right;
|
||||
}
|
||||
|
||||
if (dirtyArea.bottom == _userPixelData.h && _userPixelData.h != _textureData.h) {
|
||||
const byte *src = (const byte *)_textureData.getBasePtr(dirtyArea.left, _userPixelData.h - 1);
|
||||
byte *dst = (byte *)_textureData.getBasePtr(dirtyArea.left, _userPixelData.h);
|
||||
memcpy(dst, src, dirtyArea.width() * _textureData.format.bytesPerPixel);
|
||||
|
||||
// Extend the dirty area.
|
||||
++dirtyArea.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
_glTexture.updateArea(dirtyArea, _textureData);
|
||||
|
||||
// We should have handled everything, thus not dirty anymore.
|
||||
clearDirty();
|
||||
}
|
||||
|
||||
FakeTextureSurface::FakeTextureSurface(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format, const Graphics::PixelFormat &fakeFormat)
|
||||
: TextureSurface(glIntFormat, glFormat, glType, format),
|
||||
_fakeFormat(fakeFormat),
|
||||
_rgbData(),
|
||||
_blitFunc(nullptr),
|
||||
_palette(nullptr),
|
||||
_mask(nullptr) {
|
||||
if (_fakeFormat.isCLUT8()) {
|
||||
_palette = new uint32[256]();
|
||||
} else {
|
||||
_blitFunc = Graphics::getFastBlitFunc(format, fakeFormat);
|
||||
}
|
||||
}
|
||||
|
||||
FakeTextureSurface::~FakeTextureSurface() {
|
||||
delete[] _palette;
|
||||
delete[] _mask;
|
||||
_palette = nullptr;
|
||||
_rgbData.free();
|
||||
}
|
||||
|
||||
void FakeTextureSurface::allocate(uint width, uint height) {
|
||||
TextureSurface::allocate(width, height);
|
||||
|
||||
// We only need to reinitialize our surface when the output size
|
||||
// changed.
|
||||
if (width == (uint)_rgbData.w && height == (uint)_rgbData.h) {
|
||||
return;
|
||||
}
|
||||
|
||||
_rgbData.create(width, height, getFormat());
|
||||
}
|
||||
|
||||
void FakeTextureSurface::setMask(const byte *mask) {
|
||||
if (mask) {
|
||||
const uint numPixels = _rgbData.w * _rgbData.h;
|
||||
|
||||
if (!_mask)
|
||||
_mask = new byte[numPixels];
|
||||
|
||||
memcpy(_mask, mask, numPixels);
|
||||
} else {
|
||||
delete[] _mask;
|
||||
_mask = nullptr;
|
||||
}
|
||||
|
||||
flagDirty();
|
||||
}
|
||||
|
||||
void FakeTextureSurface::setColorKey(uint colorKey) {
|
||||
if (!_palette)
|
||||
return;
|
||||
|
||||
// The key color is set to black so the color value is pre-multiplied with the alpha value
|
||||
// to avoid color fringes due to filtering.
|
||||
// Erasing the color data is not a problem as the palette is always fully re-initialized
|
||||
// before setting the key color.
|
||||
uint32 *palette = _palette + colorKey;
|
||||
*palette = 0;
|
||||
|
||||
// A palette changes means we need to refresh the whole surface.
|
||||
flagDirty();
|
||||
}
|
||||
|
||||
void FakeTextureSurface::setPalette(uint start, uint colors, const byte *palData) {
|
||||
if (!_palette)
|
||||
return;
|
||||
|
||||
Graphics::convertPaletteToMap(_palette + start, palData, colors, _format);
|
||||
|
||||
// A palette changes means we need to refresh the whole surface.
|
||||
flagDirty();
|
||||
}
|
||||
|
||||
void FakeTextureSurface::updateGLTexture() {
|
||||
if (!isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert color space.
|
||||
Graphics::Surface *outSurf = TextureSurface::getSurface();
|
||||
|
||||
const Common::Rect dirtyArea = getDirtyArea();
|
||||
|
||||
byte *dst = (byte *)outSurf->getBasePtr(dirtyArea.left, dirtyArea.top);
|
||||
const byte *src = (const byte *)_rgbData.getBasePtr(dirtyArea.left, dirtyArea.top);
|
||||
|
||||
applyPaletteAndMask(dst, src, outSurf->pitch, _rgbData.pitch, _rgbData.w, dirtyArea, outSurf->format, _rgbData.format);
|
||||
|
||||
// Do generic handling of updating the texture.
|
||||
TextureSurface::updateGLTexture();
|
||||
}
|
||||
|
||||
void FakeTextureSurface::applyPaletteAndMask(byte *dst, const byte *src, uint dstPitch, uint srcPitch, uint srcWidth, const Common::Rect &dirtyArea, const Graphics::PixelFormat &dstFormat, const Graphics::PixelFormat &srcFormat) const {
|
||||
if (_palette) {
|
||||
Graphics::crossBlitMap(dst, src, dstPitch, srcPitch, dirtyArea.width(), dirtyArea.height(), dstFormat.bytesPerPixel, _palette);
|
||||
} else if (_blitFunc) {
|
||||
_blitFunc(dst, src, dstPitch, srcPitch, dirtyArea.width(), dirtyArea.height());
|
||||
} else {
|
||||
Graphics::crossBlit(dst, src, dstPitch, srcPitch, dirtyArea.width(), dirtyArea.height(), dstFormat, srcFormat);
|
||||
}
|
||||
|
||||
if (_mask) {
|
||||
uint maskPitch = srcWidth;
|
||||
uint dirtyWidth = dirtyArea.width();
|
||||
byte destBPP = dstFormat.bytesPerPixel;
|
||||
|
||||
const byte *maskRowStart = (_mask + dirtyArea.top * maskPitch + dirtyArea.left);
|
||||
byte *dstRowStart = dst;
|
||||
|
||||
for (uint y = dirtyArea.top; y < static_cast<uint>(dirtyArea.bottom); y++) {
|
||||
if (destBPP == 2) {
|
||||
for (uint x = 0; x < dirtyWidth; x++) {
|
||||
if (!maskRowStart[x])
|
||||
reinterpret_cast<uint16 *>(dstRowStart)[x] = 0;
|
||||
}
|
||||
} else if (destBPP == 4) {
|
||||
for (uint x = 0; x < dirtyWidth; x++) {
|
||||
if (!maskRowStart[x])
|
||||
reinterpret_cast<uint32 *>(dstRowStart)[x] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dstRowStart += dstPitch;
|
||||
maskRowStart += maskPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextureSurfaceRGB555::TextureSurfaceRGB555()
|
||||
: FakeTextureSurface(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) {
|
||||
}
|
||||
|
||||
void TextureSurfaceRGB555::updateGLTexture() {
|
||||
if (!isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert color space.
|
||||
Graphics::Surface *outSurf = TextureSurface::getSurface();
|
||||
|
||||
const Common::Rect dirtyArea = getDirtyArea();
|
||||
|
||||
uint16 *dst = (uint16 *)outSurf->getBasePtr(dirtyArea.left, dirtyArea.top);
|
||||
const uint dstAdd = outSurf->pitch - 2 * dirtyArea.width();
|
||||
|
||||
const uint16 *src = (const uint16 *)_rgbData.getBasePtr(dirtyArea.left, dirtyArea.top);
|
||||
const uint srcAdd = _rgbData.pitch - 2 * dirtyArea.width();
|
||||
|
||||
for (int height = dirtyArea.height(); height > 0; --height) {
|
||||
for (int width = dirtyArea.width(); width > 0; --width) {
|
||||
const uint16 color = *src++;
|
||||
|
||||
*dst++ = ((color & 0x7C00) << 1) // R
|
||||
| (((color & 0x03E0) << 1) | ((color & 0x0200) >> 4)) // G
|
||||
| (color & 0x001F); // B
|
||||
}
|
||||
|
||||
src = (const uint16 *)((const byte *)src + srcAdd);
|
||||
dst = (uint16 *)((byte *)dst + dstAdd);
|
||||
}
|
||||
|
||||
// Do generic handling of updating the texture.
|
||||
TextureSurface::updateGLTexture();
|
||||
}
|
||||
|
||||
#ifdef USE_SCALERS
|
||||
|
||||
ScaledTextureSurface::ScaledTextureSurface(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format, const Graphics::PixelFormat &fakeFormat)
|
||||
: FakeTextureSurface(glIntFormat, glFormat, glType, format, fakeFormat), _convData(nullptr), _scaler(nullptr), _scalerIndex(0), _scaleFactor(1), _extraPixels(0) {
|
||||
}
|
||||
|
||||
ScaledTextureSurface::~ScaledTextureSurface() {
|
||||
delete _scaler;
|
||||
|
||||
if (_convData) {
|
||||
_convData->free();
|
||||
delete _convData;
|
||||
}
|
||||
}
|
||||
|
||||
void ScaledTextureSurface::allocate(uint width, uint height) {
|
||||
TextureSurface::allocate(width * _scaleFactor, height * _scaleFactor);
|
||||
|
||||
// We only need to reinitialize our surface when the output size
|
||||
// changed.
|
||||
if (width != (uint)_rgbData.w || height != (uint)_rgbData.h) {
|
||||
_rgbData.create(width, height, _fakeFormat);
|
||||
}
|
||||
|
||||
if (_format != _fakeFormat || _extraPixels != 0) {
|
||||
if (!_convData)
|
||||
_convData = new Graphics::Surface();
|
||||
|
||||
_convData->create(width + (_extraPixels * 2), height + (_extraPixels * 2), _format);
|
||||
} else if (_convData) {
|
||||
_convData->free();
|
||||
delete _convData;
|
||||
_convData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ScaledTextureSurface::updateGLTexture() {
|
||||
if (!isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert color space.
|
||||
Graphics::Surface *outSurf = TextureSurface::getSurface();
|
||||
|
||||
Common::Rect dirtyArea = getDirtyArea();
|
||||
|
||||
// Extend the dirty region for scalers
|
||||
// that "smear" the screen, e.g. 2xSAI
|
||||
dirtyArea.grow(_extraPixels);
|
||||
dirtyArea.clip(Common::Rect(0, 0, _rgbData.w, _rgbData.h));
|
||||
|
||||
const byte *src = (const byte *)_rgbData.getBasePtr(dirtyArea.left, dirtyArea.top);
|
||||
uint srcPitch = _rgbData.pitch;
|
||||
byte *dst;
|
||||
uint dstPitch;
|
||||
|
||||
if (_convData) {
|
||||
dst = (byte *)_convData->getBasePtr(dirtyArea.left + _extraPixels, dirtyArea.top + _extraPixels);
|
||||
dstPitch = _convData->pitch;
|
||||
|
||||
applyPaletteAndMask(dst, src, dstPitch, srcPitch, _rgbData.w, dirtyArea, _convData->format, _rgbData.format);
|
||||
|
||||
src = dst;
|
||||
srcPitch = dstPitch;
|
||||
}
|
||||
|
||||
dst = (byte *)outSurf->getBasePtr(dirtyArea.left * _scaleFactor, dirtyArea.top * _scaleFactor);
|
||||
dstPitch = outSurf->pitch;
|
||||
|
||||
if (_scaler && (uint)dirtyArea.height() >= _extraPixels) {
|
||||
_scaler->scale(src, srcPitch, dst, dstPitch, dirtyArea.width(), dirtyArea.height(), dirtyArea.left, dirtyArea.top);
|
||||
} else {
|
||||
Graphics::scaleBlit(dst, src, dstPitch, srcPitch,
|
||||
dirtyArea.width() * _scaleFactor, dirtyArea.height() * _scaleFactor,
|
||||
dirtyArea.width(), dirtyArea.height(), outSurf->format);
|
||||
}
|
||||
|
||||
dirtyArea.left *= _scaleFactor;
|
||||
dirtyArea.right *= _scaleFactor;
|
||||
dirtyArea.top *= _scaleFactor;
|
||||
dirtyArea.bottom *= _scaleFactor;
|
||||
|
||||
// Do generic handling of updating the texture.
|
||||
TextureSurface::updateGLTexture(dirtyArea);
|
||||
}
|
||||
|
||||
void ScaledTextureSurface::setScaler(uint scalerIndex, int scaleFactor) {
|
||||
const PluginList &scalerPlugins = ScalerMan.getPlugins();
|
||||
const ScalerPluginObject &scalerPlugin = scalerPlugins[scalerIndex]->get<ScalerPluginObject>();
|
||||
|
||||
// If the scalerIndex has changed, change scaler plugins
|
||||
if (_scaler && scalerIndex != _scalerIndex) {
|
||||
delete _scaler;
|
||||
_scaler = nullptr;
|
||||
}
|
||||
|
||||
if (!_scaler) {
|
||||
_scaler = scalerPlugin.createInstance(_format);
|
||||
}
|
||||
_scaler->setFactor(scaleFactor);
|
||||
|
||||
_scalerIndex = scalerIndex;
|
||||
_scaleFactor = _scaler->getFactor();
|
||||
_extraPixels = scalerPlugin.extraPixels();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
|
||||
// _clut8Texture needs 8 bits internal precision, otherwise graphics glitches
|
||||
// can occur. GL_ALPHA does not have any internal precision requirements.
|
||||
// However, in practice (according to fuzzie) it's 8bit. If we run into
|
||||
// problems, we need to switch to GL_R8 and GL_RED, but that is only supported
|
||||
// for ARB_texture_rg and GLES3+ (EXT_rexture_rg does not support GL_R8).
|
||||
TextureSurfaceCLUT8GPU::TextureSurfaceCLUT8GPU()
|
||||
: _clut8Texture(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE),
|
||||
_paletteTexture(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE),
|
||||
_target(new TextureTarget()), _clut8Pipeline(new CLUT8LookUpPipeline()),
|
||||
_clut8Vertices(), _clut8Data(), _userPixelData(), _palette(),
|
||||
_paletteDirty(false) {
|
||||
// Allocate space for 256 colors.
|
||||
_paletteTexture.setSize(256, 1);
|
||||
|
||||
// Setup pipeline.
|
||||
_clut8Pipeline->setFramebuffer(_target);
|
||||
_clut8Pipeline->setPaletteTexture(&_paletteTexture);
|
||||
_clut8Pipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
TextureSurfaceCLUT8GPU::~TextureSurfaceCLUT8GPU() {
|
||||
delete _clut8Pipeline;
|
||||
delete _target;
|
||||
_clut8Data.free();
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::destroy() {
|
||||
_clut8Texture.destroy();
|
||||
_paletteTexture.destroy();
|
||||
_target->destroy();
|
||||
delete _clut8Pipeline;
|
||||
_clut8Pipeline = nullptr;
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::recreate() {
|
||||
_clut8Texture.create();
|
||||
_paletteTexture.create();
|
||||
_target->create();
|
||||
|
||||
// In case image date exists assure it will be completely refreshed next
|
||||
// time.
|
||||
if (_clut8Data.getPixels()) {
|
||||
flagDirty();
|
||||
_paletteDirty = true;
|
||||
}
|
||||
|
||||
if (_clut8Pipeline == nullptr) {
|
||||
_clut8Pipeline = new CLUT8LookUpPipeline();
|
||||
// Setup pipeline.
|
||||
_clut8Pipeline->setFramebuffer(_target);
|
||||
_clut8Pipeline->setPaletteTexture(&_paletteTexture);
|
||||
_clut8Pipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::enableLinearFiltering(bool enable) {
|
||||
_target->getTexture()->enableLinearFiltering(enable);
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::setRotation(Common::RotationMode rotation) {
|
||||
_target->getTexture()->setRotation(rotation);
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::allocate(uint width, uint height) {
|
||||
// Assure the texture can contain our user data.
|
||||
_clut8Texture.setSize(width, height);
|
||||
_target->setSize(width, height);
|
||||
|
||||
// In case the needed texture dimension changed we will reinitialize the
|
||||
// texture data buffer.
|
||||
if (_clut8Texture.getWidth() != (uint)_clut8Data.w || _clut8Texture.getHeight() != (uint)_clut8Data.h) {
|
||||
// Create a buffer for the texture data.
|
||||
_clut8Data.create(_clut8Texture.getWidth(), _clut8Texture.getHeight(), Graphics::PixelFormat::createFormatCLUT8());
|
||||
}
|
||||
|
||||
// Create a sub-buffer for raw access.
|
||||
_userPixelData = _clut8Data.getSubArea(Common::Rect(width, height));
|
||||
|
||||
// Setup structures for internal rendering to _glTexture.
|
||||
_clut8Vertices[0] = 0;
|
||||
_clut8Vertices[1] = 0;
|
||||
|
||||
_clut8Vertices[2] = width;
|
||||
_clut8Vertices[3] = 0;
|
||||
|
||||
_clut8Vertices[4] = 0;
|
||||
_clut8Vertices[5] = height;
|
||||
|
||||
_clut8Vertices[6] = width;
|
||||
_clut8Vertices[7] = height;
|
||||
|
||||
// The whole texture is dirty after we changed the size. This fixes
|
||||
// multiple texture size changes without any actual update in between.
|
||||
// Without this we might try to write a too big texture into the GL
|
||||
// texture.
|
||||
flagDirty();
|
||||
}
|
||||
|
||||
Graphics::PixelFormat TextureSurfaceCLUT8GPU::getFormat() const {
|
||||
return Graphics::PixelFormat::createFormatCLUT8();
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::setColorKey(uint colorKey) {
|
||||
// The key color is set to black so the color value is pre-multiplied with the alpha value
|
||||
// to avoid color fringes due to filtering.
|
||||
// Erasing the color data is not a problem as the palette is always fully re-initialized
|
||||
// before setting the key color.
|
||||
_palette[colorKey * 4 ] = 0x00;
|
||||
_palette[colorKey * 4 + 1] = 0x00;
|
||||
_palette[colorKey * 4 + 2] = 0x00;
|
||||
_palette[colorKey * 4 + 3] = 0x00;
|
||||
|
||||
_paletteDirty = true;
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::setPalette(uint start, uint colors, const byte *palData) {
|
||||
byte *dst = _palette + start * 4;
|
||||
|
||||
while (colors-- > 0) {
|
||||
memcpy(dst, palData, 3);
|
||||
dst[3] = 0xFF;
|
||||
|
||||
dst += 4;
|
||||
palData += 3;
|
||||
}
|
||||
|
||||
_paletteDirty = true;
|
||||
}
|
||||
|
||||
const Texture &TextureSurfaceCLUT8GPU::getGLTexture() const {
|
||||
return *_target->getTexture();
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::updateGLTexture() {
|
||||
const bool needLookUp = Surface::isDirty() || _paletteDirty;
|
||||
|
||||
// Update CLUT8 texture if necessary.
|
||||
if (Surface::isDirty()) {
|
||||
_clut8Texture.updateArea(getDirtyArea(), _clut8Data);
|
||||
clearDirty();
|
||||
}
|
||||
|
||||
// Update palette if necessary.
|
||||
if (_paletteDirty) {
|
||||
Graphics::Surface palSurface;
|
||||
palSurface.init(256, 1, 256, _palette, OpenGL::Texture::getRGBAPixelFormat());
|
||||
|
||||
_paletteTexture.updateArea(Common::Rect(256, 1), palSurface);
|
||||
_paletteDirty = false;
|
||||
}
|
||||
|
||||
// In case any data changed, do color look up and store result in _target.
|
||||
if (needLookUp) {
|
||||
lookUpColors();
|
||||
}
|
||||
}
|
||||
|
||||
void TextureSurfaceCLUT8GPU::lookUpColors() {
|
||||
// Setup pipeline to do color look up.
|
||||
_clut8Pipeline->activate();
|
||||
|
||||
// Do color look up.
|
||||
_clut8Pipeline->drawTexture(_clut8Texture, _clut8Vertices);
|
||||
|
||||
_clut8Pipeline->deactivate();
|
||||
}
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
} // End of namespace OpenGL
|
||||
341
backends/graphics/opengl/texture.h
Normal file
341
backends/graphics/opengl/texture.h
Normal file
@@ -0,0 +1,341 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGL_TEXTURE_H
|
||||
#define BACKENDS_GRAPHICS_OPENGL_TEXTURE_H
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
#include "graphics/opengl/context.h"
|
||||
#include "graphics/opengl/texture.h"
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/blit.h"
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "common/rotationmode.h"
|
||||
|
||||
class Scaler;
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
/**
|
||||
* Interface for OpenGL implementations of a 2D surface.
|
||||
*/
|
||||
class Surface {
|
||||
public:
|
||||
Surface();
|
||||
virtual ~Surface() {}
|
||||
|
||||
/**
|
||||
* Destroy OpenGL description of surface.
|
||||
*/
|
||||
virtual void destroy() = 0;
|
||||
|
||||
/**
|
||||
* Recreate OpenGL description of surface.
|
||||
*/
|
||||
virtual void recreate() = 0;
|
||||
|
||||
/**
|
||||
* Enable or disable linear texture filtering.
|
||||
*
|
||||
* @param enable true to enable and false to disable.
|
||||
*/
|
||||
virtual void enableLinearFiltering(bool enable) = 0;
|
||||
|
||||
/**
|
||||
* Sets the rotate parameter of the texture
|
||||
*
|
||||
* @param rotation How to rotate the texture
|
||||
*/
|
||||
virtual void setRotation(Common::RotationMode rotation) = 0;
|
||||
|
||||
/**
|
||||
* Allocate storage for surface.
|
||||
*
|
||||
* @param width The desired logical width.
|
||||
* @param height The desired logical height.
|
||||
*/
|
||||
virtual void allocate(uint width, uint height) = 0;
|
||||
|
||||
/**
|
||||
* Assign a mask to the surface, where a byte value of 0 is black with 0 alpha and 1 is the normal color.
|
||||
*
|
||||
* @param mask The mask data.
|
||||
*/
|
||||
virtual void setMask(const byte *mask) {}
|
||||
|
||||
/**
|
||||
* Copy image data to the surface.
|
||||
*
|
||||
* The format of the input data needs to match the format returned by
|
||||
* getFormat.
|
||||
*
|
||||
* @param x X coordinate of upper left corner to copy data to.
|
||||
* @param y Y coordinate of upper left corner to copy data to.
|
||||
* @param w Width of the image data to copy.
|
||||
* @param h Height of the image data to copy.
|
||||
* @param src Pointer to image data.
|
||||
* @param srcPitch The number of bytes in a row of the image data.
|
||||
*/
|
||||
void copyRectToTexture(uint x, uint y, uint w, uint h, const void *src, uint srcPitch);
|
||||
|
||||
/**
|
||||
* Fill the surface with a fixed color.
|
||||
*
|
||||
* @param color Color value in format returned by getFormat.
|
||||
*/
|
||||
void fill(uint32 color);
|
||||
void fill(const Common::Rect &r, uint32 color);
|
||||
|
||||
void flagDirty() { _allDirty = true; }
|
||||
virtual bool isDirty() const { return _allDirty || !_dirtyArea.isEmpty(); }
|
||||
|
||||
virtual uint getWidth() const = 0;
|
||||
virtual uint getHeight() const = 0;
|
||||
|
||||
/**
|
||||
* @return The logical format of the texture data.
|
||||
*/
|
||||
virtual Graphics::PixelFormat getFormat() const = 0;
|
||||
|
||||
virtual Graphics::Surface *getSurface() = 0;
|
||||
virtual const Graphics::Surface *getSurface() const = 0;
|
||||
|
||||
/**
|
||||
* @return Whether the surface is having a palette.
|
||||
*/
|
||||
virtual bool hasPalette() const { return false; }
|
||||
|
||||
/**
|
||||
* Set color key for paletted textures.
|
||||
*
|
||||
* This needs to be called after any palette update affecting the color
|
||||
* key. Calling this multiple times will result in multiple color indices
|
||||
* to be treated as color keys.
|
||||
*/
|
||||
virtual void setColorKey(uint colorKey) {}
|
||||
virtual void setPalette(uint start, uint colors, const byte *palData) {}
|
||||
|
||||
virtual void setScaler(uint scalerIndex, int scaleFactor) {}
|
||||
|
||||
/**
|
||||
* Update underlying OpenGL texture to reflect current state.
|
||||
*/
|
||||
virtual void updateGLTexture() = 0;
|
||||
|
||||
/**
|
||||
* Obtain underlying OpenGL texture.
|
||||
*/
|
||||
virtual const Texture &getGLTexture() const = 0;
|
||||
protected:
|
||||
void clearDirty() { _allDirty = false; _dirtyArea = Common::Rect(); }
|
||||
|
||||
void addDirtyArea(const Common::Rect &r);
|
||||
Common::Rect getDirtyArea() const;
|
||||
private:
|
||||
bool _allDirty;
|
||||
Common::Rect _dirtyArea;
|
||||
};
|
||||
|
||||
/**
|
||||
* An OpenGL texture wrapper. It automatically takes care of all OpenGL
|
||||
* texture handling issues and also provides access to the texture data.
|
||||
*/
|
||||
class TextureSurface : public Surface {
|
||||
public:
|
||||
/**
|
||||
* Create a new texture with the specific internal format.
|
||||
*
|
||||
* @param glIntFormat The internal format to use.
|
||||
* @param glFormat The input format.
|
||||
* @param glType The input type.
|
||||
* @param format The format used for the texture input.
|
||||
*/
|
||||
TextureSurface(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format);
|
||||
~TextureSurface() override;
|
||||
|
||||
void destroy() override;
|
||||
|
||||
void recreate() override;
|
||||
|
||||
void enableLinearFiltering(bool enable) override;
|
||||
void setRotation(Common::RotationMode rotation) override;
|
||||
|
||||
void allocate(uint width, uint height) override;
|
||||
|
||||
uint getWidth() const override { return _userPixelData.w; }
|
||||
uint getHeight() const override { return _userPixelData.h; }
|
||||
|
||||
/**
|
||||
* @return The logical format of the texture data.
|
||||
*/
|
||||
Graphics::PixelFormat getFormat() const override { return _format; }
|
||||
|
||||
Graphics::Surface *getSurface() override { return &_userPixelData; }
|
||||
const Graphics::Surface *getSurface() const override { return &_userPixelData; }
|
||||
|
||||
void updateGLTexture() override;
|
||||
const Texture &getGLTexture() const override { return _glTexture; }
|
||||
protected:
|
||||
const Graphics::PixelFormat _format;
|
||||
|
||||
void updateGLTexture(Common::Rect &dirtyArea);
|
||||
|
||||
private:
|
||||
Texture _glTexture;
|
||||
|
||||
Graphics::Surface _textureData;
|
||||
Graphics::Surface _userPixelData;
|
||||
};
|
||||
|
||||
class FakeTextureSurface : public TextureSurface {
|
||||
public:
|
||||
FakeTextureSurface(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format, const Graphics::PixelFormat &fakeFormat);
|
||||
~FakeTextureSurface() override;
|
||||
|
||||
void allocate(uint width, uint height) override;
|
||||
void setMask(const byte *mask) override;
|
||||
|
||||
Graphics::PixelFormat getFormat() const override { return _fakeFormat; }
|
||||
|
||||
bool hasPalette() const override { return (_palette != nullptr); }
|
||||
|
||||
void setColorKey(uint colorKey) override;
|
||||
void setPalette(uint start, uint colors, const byte *palData) override;
|
||||
|
||||
Graphics::Surface *getSurface() override { return &_rgbData; }
|
||||
const Graphics::Surface *getSurface() const override { return &_rgbData; }
|
||||
|
||||
void updateGLTexture() override;
|
||||
protected:
|
||||
void applyPaletteAndMask(byte *dst, const byte *src, uint dstPitch, uint srcPitch, uint srcWidth, const Common::Rect &dirtyArea, const Graphics::PixelFormat &dstFormat, const Graphics::PixelFormat &srcFormat) const;
|
||||
|
||||
Graphics::Surface _rgbData;
|
||||
Graphics::PixelFormat _fakeFormat;
|
||||
Graphics::FastBlitFunc _blitFunc;
|
||||
uint32 *_palette;
|
||||
uint8 *_mask;
|
||||
};
|
||||
|
||||
class TextureSurfaceRGB555 : public FakeTextureSurface {
|
||||
public:
|
||||
TextureSurfaceRGB555();
|
||||
~TextureSurfaceRGB555() override {}
|
||||
|
||||
void updateGLTexture() override;
|
||||
};
|
||||
|
||||
#ifdef USE_SCALERS
|
||||
class ScaledTextureSurface : public FakeTextureSurface {
|
||||
public:
|
||||
ScaledTextureSurface(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format, const Graphics::PixelFormat &fakeFormat);
|
||||
~ScaledTextureSurface() override;
|
||||
|
||||
void allocate(uint width, uint height) override;
|
||||
|
||||
uint getWidth() const override { return _rgbData.w; }
|
||||
uint getHeight() const override { return _rgbData.h; }
|
||||
Graphics::PixelFormat getFormat() const override { return _fakeFormat; }
|
||||
|
||||
bool hasPalette() const override { return (_palette != nullptr); }
|
||||
|
||||
Graphics::Surface *getSurface() override { return &_rgbData; }
|
||||
const Graphics::Surface *getSurface() const override { return &_rgbData; }
|
||||
|
||||
void updateGLTexture() override;
|
||||
|
||||
void setScaler(uint scalerIndex, int scaleFactor) override;
|
||||
protected:
|
||||
Graphics::Surface *_convData;
|
||||
Scaler *_scaler;
|
||||
uint _scalerIndex;
|
||||
uint _extraPixels;
|
||||
uint _scaleFactor;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !USE_FORCED_GLES
|
||||
class TextureTarget;
|
||||
class CLUT8LookUpPipeline;
|
||||
|
||||
class TextureSurfaceCLUT8GPU : public Surface {
|
||||
public:
|
||||
TextureSurfaceCLUT8GPU();
|
||||
~TextureSurfaceCLUT8GPU() override;
|
||||
|
||||
void destroy() override;
|
||||
|
||||
void recreate() override;
|
||||
|
||||
void enableLinearFiltering(bool enable) override;
|
||||
void setRotation(Common::RotationMode rotation) override;
|
||||
|
||||
void allocate(uint width, uint height) override;
|
||||
|
||||
bool isDirty() const override { return _paletteDirty || Surface::isDirty(); }
|
||||
|
||||
uint getWidth() const override { return _userPixelData.w; }
|
||||
uint getHeight() const override { return _userPixelData.h; }
|
||||
|
||||
Graphics::PixelFormat getFormat() const override;
|
||||
|
||||
bool hasPalette() const override { return true; }
|
||||
|
||||
void setColorKey(uint colorKey) override;
|
||||
void setPalette(uint start, uint colors, const byte *palData) override;
|
||||
|
||||
Graphics::Surface *getSurface() override { return &_userPixelData; }
|
||||
const Graphics::Surface *getSurface() const override { return &_userPixelData; }
|
||||
|
||||
void updateGLTexture() override;
|
||||
const Texture &getGLTexture() const override;
|
||||
|
||||
static bool isSupportedByContext() {
|
||||
return OpenGLContext.shadersSupported
|
||||
&& OpenGLContext.multitextureSupported
|
||||
&& OpenGLContext.framebufferObjectSupported
|
||||
// With 2^-8 precision this is too prone to approximation errors
|
||||
&& OpenGLContext.textureLookupPrecision > 8;
|
||||
}
|
||||
private:
|
||||
void lookUpColors();
|
||||
|
||||
Texture _clut8Texture;
|
||||
Texture _paletteTexture;
|
||||
|
||||
TextureTarget *_target;
|
||||
CLUT8LookUpPipeline *_clut8Pipeline;
|
||||
|
||||
GLfloat _clut8Vertices[4*2];
|
||||
|
||||
Graphics::Surface _clut8Data;
|
||||
Graphics::Surface _userPixelData;
|
||||
|
||||
byte _palette[4 * 256];
|
||||
bool _paletteDirty;
|
||||
};
|
||||
#endif // !USE_FORCED_GLES
|
||||
|
||||
} // End of namespace OpenGL
|
||||
|
||||
#endif
|
||||
1110
backends/graphics/openglsdl/openglsdl-graphics.cpp
Normal file
1110
backends/graphics/openglsdl/openglsdl-graphics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
146
backends/graphics/openglsdl/openglsdl-graphics.h
Normal file
146
backends/graphics/openglsdl/openglsdl-graphics.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/* 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 BACKENDS_GRAPHICS_OPENGLSDL_OPENGLSDL_GRAPHICS_H
|
||||
#define BACKENDS_GRAPHICS_OPENGLSDL_OPENGLSDL_GRAPHICS_H
|
||||
|
||||
#include "backends/graphics/opengl/opengl-graphics.h"
|
||||
#include "backends/graphics/sdl/sdl-graphics.h"
|
||||
#include "backends/platform/sdl/sdl-sys.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/events.h"
|
||||
|
||||
class OpenGLSdlGraphicsManager : public OpenGL::OpenGLGraphicsManager, public SdlGraphicsManager {
|
||||
public:
|
||||
OpenGLSdlGraphicsManager(SdlEventSource *eventSource, SdlWindow *window);
|
||||
virtual ~OpenGLSdlGraphicsManager();
|
||||
|
||||
bool hasFeature(OSystem::Feature f) const override;
|
||||
void setFeatureState(OSystem::Feature f, bool enable) override;
|
||||
bool getFeatureState(OSystem::Feature f) const override;
|
||||
|
||||
void initSize(uint w, uint h, const Graphics::PixelFormat *format) override;
|
||||
void updateScreen() override;
|
||||
|
||||
float getHiDPIScreenFactor() const override;
|
||||
|
||||
// EventObserver API
|
||||
bool notifyEvent(const Common::Event &event) override;
|
||||
|
||||
// SdlGraphicsManager API
|
||||
void notifyVideoExpose() override;
|
||||
void notifyResize(const int width, const int height) override;
|
||||
|
||||
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
void *getImGuiTexture(const Graphics::Surface &image, const byte *palette, int palCount) override;
|
||||
void freeImGuiTexture(void *texture) override;
|
||||
#endif
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
void destroyingWindow() override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool loadVideoMode(uint requestedWidth, uint requestedHeight, bool resizable, int antialiasing) override;
|
||||
|
||||
void refreshScreen() override;
|
||||
|
||||
void handleResizeImpl(const int width, const int height) override;
|
||||
|
||||
bool saveScreenshot(const Common::Path &filename) const override;
|
||||
|
||||
bool canSwitchFullscreen() const override;
|
||||
|
||||
private:
|
||||
bool setupMode(uint width, uint height);
|
||||
|
||||
void deinitOpenGLContext();
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
int _glContextProfileMask, _glContextMajor, _glContextMinor;
|
||||
|
||||
SDL_GLContext _glContext;
|
||||
#else
|
||||
uint32 _lastVideoModeLoad;
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
/**
|
||||
* See https://registry.khronos.org/webgl/specs/latest/1.0/#2 :
|
||||
* " By default, after compositing the contents of the drawing buffer shall be cleared to their default values [...]
|
||||
* Techniques like synchronous drawing buffer access (e.g., calling readPixels or toDataURL in the same function
|
||||
* that renders to the drawing buffer) can be used to get the contents of the drawing buffer "
|
||||
*
|
||||
* This means we need to take the screenshot at the correct time, which we do by queueing taking the screenshot
|
||||
* for the next frame instead of taking it right away.
|
||||
*/
|
||||
bool _queuedScreenshot = false;
|
||||
void saveScreenshot() override;
|
||||
#endif
|
||||
|
||||
OpenGL::ContextType _glContextType;
|
||||
bool _resizable;
|
||||
int _requestedAntialiasing;
|
||||
int _effectiveAntialiasing;
|
||||
|
||||
uint _forceFrameUpdate = 0;
|
||||
uint _lastRequestedWidth;
|
||||
uint _lastRequestedHeight;
|
||||
uint _graphicsScale;
|
||||
bool _gotResize;
|
||||
|
||||
bool _vsync;
|
||||
bool _wantsFullScreen;
|
||||
uint _ignoreResizeEvents;
|
||||
|
||||
struct VideoMode {
|
||||
VideoMode() : width(0), height(0) {}
|
||||
VideoMode(uint w, uint h) : width(w), height(h) {}
|
||||
|
||||
bool operator<(const VideoMode &right) const {
|
||||
if (width < right.width) {
|
||||
return true;
|
||||
} else if (width == right.width && height < right.height) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const VideoMode &right) const {
|
||||
return width == right.width && height == right.height;
|
||||
}
|
||||
|
||||
bool operator!=(const VideoMode &right) const {
|
||||
return !(*this == right);
|
||||
}
|
||||
|
||||
uint width, height;
|
||||
};
|
||||
typedef Common::Array<VideoMode> VideoModeArray;
|
||||
VideoModeArray _fullscreenVideoModes;
|
||||
|
||||
uint _desiredFullscreenWidth;
|
||||
uint _desiredFullscreenHeight;
|
||||
};
|
||||
|
||||
#endif
|
||||
72
backends/graphics/openpandora/op-graphics.cpp
Normal file
72
backends/graphics/openpandora/op-graphics.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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/scummsys.h"
|
||||
|
||||
#if defined(OPENPANDORA)
|
||||
|
||||
#include "backends/graphics/openpandora/op-graphics.h"
|
||||
#include "backends/events/openpandora/op-events.h"
|
||||
#include "graphics/scaler/aspect.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
static SDL_Cursor *hiddenCursor;
|
||||
|
||||
OPGraphicsManager::OPGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window)
|
||||
: SurfaceSdlGraphicsManager(sdlEventSource, window) {
|
||||
}
|
||||
|
||||
bool OPGraphicsManager::loadGFXMode() {
|
||||
|
||||
uint8_t hiddenCursorData = 0;
|
||||
hiddenCursor = SDL_CreateCursor(&hiddenCursorData, &hiddenCursorData, 8, 1, 0, 0);
|
||||
|
||||
/* On the OpenPandora we need to work around an SDL assumption that
|
||||
returns relative mouse coordinates when you get to the screen
|
||||
edges using the touchscreen. The workaround is to set a blank
|
||||
SDL cursor and not disable it (Hackish I know).
|
||||
|
||||
The root issues likes in the Windows Manager GRAB code in SDL.
|
||||
That is why the issue is not seen on framebuffer devices like the
|
||||
GP2X (there is no X window manager ;)).
|
||||
*/
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
SDL_SetCursor(hiddenCursor);
|
||||
|
||||
return SurfaceSdlGraphicsManager::loadGFXMode();
|
||||
}
|
||||
|
||||
void OPGraphicsManager::unloadGFXMode() {
|
||||
|
||||
uint8_t hiddenCursorData = 0;
|
||||
hiddenCursor = SDL_CreateCursor(&hiddenCursorData, &hiddenCursorData, 8, 1, 0, 0);
|
||||
|
||||
// Free the hidden SDL cursor created in loadGFXMode
|
||||
SDL_FreeCursor(hiddenCursor);
|
||||
|
||||
SurfaceSdlGraphicsManager::unloadGFXMode();
|
||||
}
|
||||
|
||||
void OPGraphicsManager::showSystemMouseCursor(bool visible) {
|
||||
}
|
||||
|
||||
#endif
|
||||
37
backends/graphics/openpandora/op-graphics.h
Normal file
37
backends/graphics/openpandora/op-graphics.h
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_GRAPHICS_OP_H
|
||||
#define BACKENDS_GRAPHICS_OP_H
|
||||
|
||||
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
|
||||
|
||||
class OPGraphicsManager : public SurfaceSdlGraphicsManager {
|
||||
public:
|
||||
OPGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window);
|
||||
|
||||
bool loadGFXMode() override;
|
||||
void unloadGFXMode() override;
|
||||
|
||||
void showSystemMouseCursor(bool visible) override;
|
||||
};
|
||||
|
||||
#endif /* BACKENDS_GRAPHICS_OP_H */
|
||||
77
backends/graphics/riscossdl/riscossdl-graphics.cpp
Normal file
77
backends/graphics/riscossdl/riscossdl-graphics.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/* 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/scummsys.h"
|
||||
|
||||
#if defined(RISCOS) && defined(SDL_BACKEND)
|
||||
|
||||
#include "backends/graphics/riscossdl/riscossdl-graphics.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
static OSystem::GraphicsMode s_supportedGraphicsModes[] = {
|
||||
{"surfacesdl", _s("SDL Surface"), GFX_SURFACESDL},
|
||||
{"palettesdl", _s("SDL Surface (forced 8bpp mode)"), GFX_PALETTESDL},
|
||||
{nullptr, nullptr, 0}
|
||||
};
|
||||
|
||||
const OSystem::GraphicsMode *RISCOSSdlGraphicsManager::getSupportedGraphicsModes() const {
|
||||
return s_supportedGraphicsModes;
|
||||
}
|
||||
|
||||
bool RISCOSSdlGraphicsManager::hasFeature(OSystem::Feature f) const {
|
||||
if (f == OSystem::kFeatureVSync)
|
||||
return true;
|
||||
return SurfaceSdlGraphicsManager::hasFeature(f);
|
||||
}
|
||||
|
||||
void RISCOSSdlGraphicsManager::initGraphicsSurface() {
|
||||
Uint32 flags = 0;
|
||||
int bpp = 0;
|
||||
|
||||
if (_videoMode.fullscreen)
|
||||
flags |= SDL_FULLSCREEN;
|
||||
|
||||
if (_videoMode.vsync && _videoMode.fullscreen) {
|
||||
flags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
|
||||
} else {
|
||||
/* Hardware surfaces and double buffering aren't supported in windowed mode on RISC OS. */
|
||||
flags |= SDL_SWSURFACE;
|
||||
}
|
||||
|
||||
switch (_videoMode.mode) {
|
||||
case GFX_SURFACESDL:
|
||||
bpp = 16;
|
||||
flags |= SDL_ANYFORMAT;
|
||||
break;
|
||||
case GFX_PALETTESDL:
|
||||
bpp = 8;
|
||||
flags |= SDL_HWPALETTE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_hwScreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, bpp, flags);
|
||||
_isDoubleBuf = flags & SDL_DOUBLEBUF;
|
||||
_isHwPalette = flags & SDL_HWPALETTE;
|
||||
}
|
||||
|
||||
#endif
|
||||
41
backends/graphics/riscossdl/riscossdl-graphics.h
Normal file
41
backends/graphics/riscossdl/riscossdl-graphics.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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 BACKENDS_GRAPHICS_RISCOSSDL_H
|
||||
#define BACKENDS_GRAPHICS_RISCOSSDL_H
|
||||
|
||||
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
|
||||
|
||||
enum {
|
||||
GFX_PALETTESDL = 1
|
||||
};
|
||||
|
||||
|
||||
class RISCOSSdlGraphicsManager : public SurfaceSdlGraphicsManager {
|
||||
public:
|
||||
RISCOSSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window) : SurfaceSdlGraphicsManager(sdlEventSource, window) {}
|
||||
|
||||
const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
|
||||
bool hasFeature(OSystem::Feature f) const override;
|
||||
void initGraphicsSurface() override;
|
||||
};
|
||||
|
||||
#endif /* BACKENDS_GRAPHICS_RISCOSSDL_H */
|
||||
778
backends/graphics/sdl/sdl-graphics.cpp
Normal file
778
backends/graphics/sdl/sdl-graphics.cpp
Normal file
@@ -0,0 +1,778 @@
|
||||
/* 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 "backends/graphics/sdl/sdl-graphics.h"
|
||||
#include "backends/platform/sdl/sdl-sys.h"
|
||||
#include "backends/platform/sdl/sdl.h"
|
||||
#include "backends/events/sdl/sdl-events.h"
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymap.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/translation.h"
|
||||
#include "graphics/scaler/aspect.h"
|
||||
#ifdef USE_OSD
|
||||
#include "common/translation.h"
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
#include "backends/platform/sdl/emscripten/emscripten.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
#include "backends/imgui/backends/imgui_impl_sdl3.h"
|
||||
#ifdef USE_OPENGL
|
||||
#include "backends/imgui/backends/imgui_impl_opengl3.h"
|
||||
#endif
|
||||
#ifdef USE_IMGUI_SDLRENDERER3
|
||||
#include "backends/imgui/backends/imgui_impl_sdlrenderer3.h"
|
||||
#endif
|
||||
#elif defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
#include "backends/imgui/backends/imgui_impl_sdl2.h"
|
||||
#ifdef USE_OPENGL
|
||||
#include "backends/imgui/backends/imgui_impl_opengl3.h"
|
||||
#endif
|
||||
#ifdef USE_IMGUI_SDLRENDERER2
|
||||
#include "backends/imgui/backends/imgui_impl_sdlrenderer2.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
static void getMouseState(int *x, int *y) {
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
float fx, fy;
|
||||
SDL_GetMouseState(&fx, &fy);
|
||||
*x = static_cast<int>(fx);
|
||||
*y = static_cast<int>(fy);
|
||||
#else
|
||||
SDL_GetMouseState(x, y);
|
||||
#endif
|
||||
}
|
||||
|
||||
SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source, SdlWindow *window)
|
||||
: _eventSource(source), _window(window), _hwScreen(nullptr)
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
, _allowWindowSizeReset(false), _hintedWidth(0), _hintedHeight(0), _lastFlags(0)
|
||||
#endif
|
||||
{
|
||||
ConfMan.registerDefault("fullscreen_res", "desktop");
|
||||
|
||||
getMouseState(&_cursorX, &_cursorY);
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::activateManager() {
|
||||
_eventSource->setGraphicsManager(this);
|
||||
|
||||
// Register the graphics manager as a event observer
|
||||
g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::deactivateManager() {
|
||||
// Unregister the event observer
|
||||
if (g_system->getEventManager()->getEventDispatcher()) {
|
||||
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
|
||||
}
|
||||
|
||||
_eventSource->setGraphicsManager(nullptr);
|
||||
}
|
||||
|
||||
SdlGraphicsManager::State SdlGraphicsManager::getState() const {
|
||||
State state;
|
||||
|
||||
state.screenWidth = getWidth();
|
||||
state.screenHeight = getHeight();
|
||||
state.aspectRatio = getFeatureState(OSystem::kFeatureAspectRatioCorrection);
|
||||
state.fullscreen = getFeatureState(OSystem::kFeatureFullscreenMode);
|
||||
state.cursorPalette = getFeatureState(OSystem::kFeatureCursorPalette);
|
||||
state.vsync = getFeatureState(OSystem::kFeatureVSync);
|
||||
state.rotation = _rotationMode;
|
||||
#ifdef USE_RGB_COLOR
|
||||
state.pixelFormat = getScreenFormat();
|
||||
#endif
|
||||
return state;
|
||||
}
|
||||
|
||||
bool SdlGraphicsManager::setState(const State &state) {
|
||||
beginGFXTransaction();
|
||||
#ifdef USE_RGB_COLOR
|
||||
// When switching between the SDL and OpenGL graphics manager, the list
|
||||
// of supported format changes. This means that the pixel format in the
|
||||
// state may not be supported. In that case use the preferred supported
|
||||
// pixel format instead.
|
||||
Graphics::PixelFormat format = state.pixelFormat;
|
||||
Common::List<Graphics::PixelFormat> supportedFormats = getSupportedFormats();
|
||||
if (!supportedFormats.empty() && Common::find(supportedFormats.begin(), supportedFormats.end(), format) == supportedFormats.end())
|
||||
format = supportedFormats.front();
|
||||
initSize(state.screenWidth, state.screenHeight, &format);
|
||||
#else
|
||||
initSize(state.screenWidth, state.screenHeight, nullptr);
|
||||
#endif
|
||||
setFeatureState(OSystem::kFeatureAspectRatioCorrection, state.aspectRatio);
|
||||
setFeatureState(OSystem::kFeatureFullscreenMode, state.fullscreen);
|
||||
setFeatureState(OSystem::kFeatureCursorPalette, state.cursorPalette);
|
||||
setFeatureState(OSystem::kFeatureVSync, state.vsync);
|
||||
setRotationMode(state.rotation);
|
||||
|
||||
if (endGFXTransaction() != OSystem::kTransactionSuccess) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect SdlGraphicsManager::getPreferredFullscreenResolution() {
|
||||
// Default to the desktop resolution, unless the user has set a
|
||||
// resolution in the configuration file
|
||||
const Common::String &fsres = ConfMan.get("fullscreen_res");
|
||||
if (fsres != "desktop") {
|
||||
uint newW, newH;
|
||||
int converted = sscanf(fsres.c_str(), "%ux%u", &newW, &newH);
|
||||
if (converted == 2) {
|
||||
return Common::Rect(newW, newH);
|
||||
} else {
|
||||
warning("Could not parse 'fullscreen_res' option: expected WWWxHHH, got %s", fsres.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return _window->getDesktopResolution();
|
||||
}
|
||||
|
||||
bool SdlGraphicsManager::defaultGraphicsModeConfig() const {
|
||||
const Common::ConfigManager::Domain *transientDomain = ConfMan.getDomain(Common::ConfigManager::kTransientDomain);
|
||||
if (transientDomain && transientDomain->contains("scaler")) {
|
||||
const Common::String &mode = transientDomain->getVal("scaler");
|
||||
if (!mode.equalsIgnoreCase("default")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const Common::ConfigManager::Domain *gameDomain = ConfMan.getActiveDomain();
|
||||
if (gameDomain && gameDomain->contains("scaler")) {
|
||||
const Common::String &mode = gameDomain->getVal("scaler");
|
||||
if (!mode.equalsIgnoreCase("default")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::initSizeHint(const Graphics::ModeList &modes) {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
const bool useDefault = defaultGraphicsModeConfig();
|
||||
|
||||
// This gets called from engine before they call initGraphics(), which means we cannot use getScaleFactor()
|
||||
// because the scale factor in the backend has not yet been updated to use the game settings. So directly
|
||||
// read the game settings. This may be -1, which means we want to use the default. Fortunately runGame()
|
||||
// in main.cpp sets the gaphics mode (OpenGL or SurfaceSDL) before starting the engine. So we already have
|
||||
// the correct graphics manager and we can call getDefaultScaleFactor() here.
|
||||
int scale = ConfMan.getInt("scale_factor");
|
||||
if (scale == -1) {
|
||||
scale = getDefaultScaleFactor();
|
||||
}
|
||||
|
||||
int16 bestWidth = 0, bestHeight = 0;
|
||||
const Graphics::ModeList::const_iterator end = modes.end();
|
||||
for (Graphics::ModeList::const_iterator it = modes.begin(); it != end; ++it) {
|
||||
int16 width = it->width, height = it->height;
|
||||
|
||||
// TODO: Normalize AR correction by passing a PAR in the mode list
|
||||
// instead of checking the dimensions here like this, since not all
|
||||
// 320x200/640x400 uses are with non-square pixels (e.g. DreamWeb).
|
||||
if (ConfMan.getBool("aspect_ratio")) {
|
||||
if ((width == 320 && height == 200) || (width == 640 && height == 400)) {
|
||||
height = real2Aspect(height);
|
||||
}
|
||||
}
|
||||
|
||||
if (!useDefault || width <= 320) {
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
}
|
||||
|
||||
if (bestWidth < width) {
|
||||
bestWidth = width;
|
||||
}
|
||||
|
||||
if (bestHeight < height) {
|
||||
bestHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
_hintedWidth = bestWidth;
|
||||
_hintedHeight = bestHeight;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SdlGraphicsManager::showMouse(bool visible) {
|
||||
if (visible == _cursorVisible) {
|
||||
return visible;
|
||||
}
|
||||
|
||||
bool showCursor = false;
|
||||
if (visible) {
|
||||
// _cursorX and _cursorY are currently always clipped to the active
|
||||
// area, so we need to ask SDL where the system's mouse cursor is
|
||||
// instead
|
||||
int x, y;
|
||||
getMouseState(&x, &y);
|
||||
if (!_activeArea.drawRect.contains(Common::Point(x, y))) {
|
||||
showCursor = true;
|
||||
}
|
||||
}
|
||||
showSystemMouseCursor(showCursor);
|
||||
|
||||
return WindowedGraphicsManager::showMouse(visible);
|
||||
}
|
||||
|
||||
bool SdlGraphicsManager::lockMouse(bool lock) {
|
||||
return _window->lockMouse(lock);
|
||||
}
|
||||
|
||||
bool SdlGraphicsManager::notifyMousePosition(Common::Point &mouse) {
|
||||
bool showCursor = false;
|
||||
// Currently on macOS we need to scale the events for HiDPI screen, but on
|
||||
// Windows we do not. We can find out if we need to do it by querying the
|
||||
// SDL window size vs the SDL drawable size.
|
||||
float dpiScale = _window->getSdlDpiScalingFactor();
|
||||
mouse.x = (int)(mouse.x * dpiScale + 0.5f);
|
||||
mouse.y = (int)(mouse.y * dpiScale + 0.5f);
|
||||
bool valid = true;
|
||||
if (_activeArea.drawRect.contains(mouse)) {
|
||||
_cursorLastInActiveArea = true;
|
||||
} else {
|
||||
// The right/bottom edges are not part of the drawRect. As the clipping
|
||||
// is done in drawable area coordinates, but the mouse position is set
|
||||
// in window coordinates, we need to subtract as many pixels from the
|
||||
// edges as corresponds to one pixel in the window coordinates.
|
||||
mouse.x = CLIP<int>(mouse.x, _activeArea.drawRect.left,
|
||||
_activeArea.drawRect.right - (int)(1 * dpiScale + 0.5f));
|
||||
mouse.y = CLIP<int>(mouse.y, _activeArea.drawRect.top,
|
||||
_activeArea.drawRect.bottom - (int)(1 * dpiScale + 0.5f));
|
||||
|
||||
if (_window->mouseIsGrabbed() ||
|
||||
// Keep the mouse inside the game area during dragging to prevent an
|
||||
// event mismatch where the mouseup event gets lost because it is
|
||||
// performed outside of the game area
|
||||
(_cursorLastInActiveArea && SDL_GetMouseState(nullptr, nullptr) != 0)) {
|
||||
setSystemMousePosition(mouse.x, mouse.y);
|
||||
} else {
|
||||
// Allow the in-game mouse to get a final movement event to the edge
|
||||
// of the window if the mouse was moved out of the game area
|
||||
if (_cursorLastInActiveArea) {
|
||||
_cursorLastInActiveArea = false;
|
||||
} else if (_cursorVisible) {
|
||||
// Keep sending events to the game if the cursor is invisible,
|
||||
// since otherwise if a game lets you skip a cutscene by
|
||||
// clicking and the user moved the mouse outside the active
|
||||
// area, the clicks wouldn't do anything, which would be
|
||||
// confusing
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (_cursorVisible) {
|
||||
showCursor = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showSystemMouseCursor(showCursor);
|
||||
if (valid) {
|
||||
setMousePosition(mouse.x, mouse.y);
|
||||
mouse = convertWindowToVirtual(mouse.x, mouse.y);
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::showSystemMouseCursor(bool visible) {
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
if (visible) {
|
||||
SDL_ShowCursor();
|
||||
} else {
|
||||
SDL_HideCursor();
|
||||
}
|
||||
#else
|
||||
SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::setSystemMousePosition(const int x, const int y) {
|
||||
assert(_window);
|
||||
if (!_window->warpMouseInWindow(x, y)) {
|
||||
const Common::Point mouse = convertWindowToVirtual(x, y);
|
||||
_eventSource->fakeWarpMouse(mouse.x, mouse.y);
|
||||
}
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::notifyActiveAreaChanged() {
|
||||
_window->setMouseRect(_activeArea.drawRect);
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::handleResizeImpl(const int width, const int height) {
|
||||
_forceRedraw = true;
|
||||
}
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
bool SdlGraphicsManager::createOrUpdateWindow(int width, int height, const Uint32 flags) {
|
||||
if (!_window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// width *=3;
|
||||
// height *=3;
|
||||
|
||||
// We only update the actual window when flags change (which usually means
|
||||
// fullscreen mode is entered/exited), when updates are forced so that we
|
||||
// do not reset the window size whenever a game makes a call to change the
|
||||
// size or pixel format of the internal game surface (since a user may have
|
||||
// resized the game window), or when the launcher is visible (since a user
|
||||
// may change the scaler, which should reset the window size)
|
||||
if (!_window->getSDLWindow() || _lastFlags != flags || _overlayVisible || _allowWindowSizeReset) {
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
const bool fullscreen = (flags & (SDL_WINDOW_FULLSCREEN)) != 0;
|
||||
#else
|
||||
const bool fullscreen = (flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0;
|
||||
#endif
|
||||
const bool maximized = (flags & SDL_WINDOW_MAXIMIZED);
|
||||
if (!fullscreen && !maximized) {
|
||||
if (_hintedWidth > width) {
|
||||
width = _hintedWidth;
|
||||
}
|
||||
if (_hintedHeight > height) {
|
||||
height = _hintedHeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_window->createOrUpdateWindow(width, height, flags)) {
|
||||
return false;
|
||||
}
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
if (fullscreen) {
|
||||
if (!SDL_SetWindowFullscreenMode(_window->getSDLWindow(), NULL))
|
||||
return false;
|
||||
if (!SDL_SyncWindow(_window->getSDLWindow()))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
_lastFlags = flags;
|
||||
_allowWindowSizeReset = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SdlGraphicsManager::saveScreenshot() {
|
||||
Common::String filename;
|
||||
|
||||
Common::Path screenshotsPath;
|
||||
OSystem_SDL *sdl_g_system = dynamic_cast<OSystem_SDL*>(g_system);
|
||||
if (sdl_g_system)
|
||||
screenshotsPath = sdl_g_system->getScreenshotsPath();
|
||||
|
||||
// Use the name of the running target as a base for screenshot file names
|
||||
Common::String currentTarget = ConfMan.getActiveDomainName();
|
||||
|
||||
#ifdef USE_PNG
|
||||
const char *extension = "png";
|
||||
#else
|
||||
const char *extension = "bmp";
|
||||
#endif
|
||||
|
||||
for (int n = 0;; n++) {
|
||||
filename = Common::String::format("scummvm%s%s-%05d.%s", currentTarget.empty() ? "" : "-",
|
||||
currentTarget.c_str(), n, extension);
|
||||
|
||||
Common::FSNode file = Common::FSNode(screenshotsPath.appendComponent(filename));
|
||||
if (!file.exists()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (saveScreenshot(screenshotsPath.appendComponent(filename))) {
|
||||
if (screenshotsPath.empty())
|
||||
debug("Saved screenshot '%s' in current directory", filename.c_str());
|
||||
else
|
||||
debug("Saved screenshot '%s' in directory '%s'", filename.c_str(),
|
||||
screenshotsPath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
|
||||
#ifdef USE_OSD
|
||||
if (!ConfMan.getBool("disable_saved_screenshot_osd"))
|
||||
displayMessageOnOSD(Common::U32String::format(_("Saved screenshot '%s'"), filename.c_str()));
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
// Users can't access the virtual emscripten filesystem in the browser, so we export the generated screenshot file via OSystem_Emscripten::exportFile.
|
||||
OSystem_Emscripten *emscripten_g_system = dynamic_cast<OSystem_Emscripten*>(g_system);
|
||||
emscripten_g_system->exportFile(screenshotsPath.appendComponent(filename));
|
||||
#endif
|
||||
} else {
|
||||
if (screenshotsPath.empty())
|
||||
warning("Could not save screenshot in current directory");
|
||||
else
|
||||
warning("Could not save screenshot in directory '%s'", screenshotsPath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
|
||||
#ifdef USE_OSD
|
||||
displayMessageOnOSD(_("Could not save screenshot"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool SdlGraphicsManager::notifyEvent(const Common::Event &event) {
|
||||
if (event.type != Common::EVENT_CUSTOM_BACKEND_ACTION_START) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ((CustomEventAction) event.customType) {
|
||||
case kActionToggleMouseCapture:
|
||||
getWindow()->grabMouse(!getWindow()->mouseIsGrabbed());
|
||||
return true;
|
||||
|
||||
case kActionToggleResizableWindow:
|
||||
getWindow()->setResizable(!getWindow()->resizable());
|
||||
return true;
|
||||
|
||||
case kActionToggleFullscreen:
|
||||
toggleFullScreen();
|
||||
return true;
|
||||
|
||||
case kActionSaveScreenshot:
|
||||
saveScreenshot();
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::toggleFullScreen() {
|
||||
if (!g_system->hasFeature(OSystem::kFeatureFullscreenMode) ||
|
||||
!canSwitchFullscreen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
beginGFXTransaction();
|
||||
setFeatureState(OSystem::kFeatureFullscreenMode, !getFeatureState(OSystem::kFeatureFullscreenMode));
|
||||
endGFXTransaction();
|
||||
#ifdef USE_OSD
|
||||
if (getFeatureState(OSystem::kFeatureFullscreenMode))
|
||||
displayMessageOnOSD(_("Fullscreen mode"));
|
||||
else
|
||||
displayMessageOnOSD(_("Windowed mode"));
|
||||
#endif
|
||||
}
|
||||
|
||||
Common::Keymap *SdlGraphicsManager::getKeymap() {
|
||||
using namespace Common;
|
||||
|
||||
Keymap *keymap = new Keymap(Keymap::kKeymapTypeGlobal, "sdl-graphics", _("Graphics"));
|
||||
Action *act;
|
||||
|
||||
if (g_system->hasFeature(OSystem::kFeatureFullscreenMode)) {
|
||||
act = new Action("FULS", _("Toggle fullscreen"));
|
||||
act->addDefaultInputMapping("A+RETURN");
|
||||
act->addDefaultInputMapping("A+KP_ENTER");
|
||||
act->setCustomBackendActionEvent(kActionToggleFullscreen);
|
||||
keymap->addAction(act);
|
||||
}
|
||||
|
||||
act = new Action("CAPT", _("Toggle mouse capture"));
|
||||
act->addDefaultInputMapping("C+m");
|
||||
act->setCustomBackendActionEvent(kActionToggleMouseCapture);
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Action("RSZW", _("Toggle resizable window"));
|
||||
act->addDefaultInputMapping("C+r");
|
||||
act->setCustomBackendActionEvent(kActionToggleResizableWindow);
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Action("SCRS", _("Save screenshot"));
|
||||
act->addDefaultInputMapping("A+s");
|
||||
act->setCustomBackendActionEvent(kActionSaveScreenshot);
|
||||
keymap->addAction(act);
|
||||
|
||||
if (hasFeature(OSystem::kFeatureAspectRatioCorrection)) {
|
||||
act = new Action("ASPT", _("Toggle aspect ratio correction"));
|
||||
act->addDefaultInputMapping("C+A+a");
|
||||
act->setCustomBackendActionEvent(kActionToggleAspectRatioCorrection);
|
||||
keymap->addAction(act);
|
||||
}
|
||||
|
||||
if (hasFeature(OSystem::kFeatureFilteringMode)) {
|
||||
act = new Action("FILT", _("Toggle linear filtered scaling"));
|
||||
act->addDefaultInputMapping("C+A+f");
|
||||
act->setCustomBackendActionEvent(kActionToggleFilteredScaling);
|
||||
keymap->addAction(act);
|
||||
}
|
||||
|
||||
if (hasFeature(OSystem::kFeatureStretchMode)) {
|
||||
act = new Action("STCH", _("Cycle through stretch modes"));
|
||||
act->addDefaultInputMapping("C+A+s");
|
||||
act->setCustomBackendActionEvent(kActionCycleStretchMode);
|
||||
keymap->addAction(act);
|
||||
}
|
||||
|
||||
act = new Action("SCL+", _("Increase the scale factor"));
|
||||
act->addDefaultInputMapping("C+A+PLUS");
|
||||
act->addDefaultInputMapping("C+A+KP_PLUS");
|
||||
act->setCustomBackendActionEvent(kActionIncreaseScaleFactor);
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Action("SCL-", _("Decrease the scale factor"));
|
||||
act->addDefaultInputMapping("C+A+MINUS");
|
||||
act->addDefaultInputMapping("C+A+KP_MINUS");
|
||||
act->setCustomBackendActionEvent(kActionDecreaseScaleFactor);
|
||||
keymap->addAction(act);
|
||||
|
||||
if (hasFeature(OSystem::kFeatureScalers)) {
|
||||
act = new Action("FLTN", _("Switch to the next scaler"));
|
||||
act->addDefaultInputMapping("C+A+0");
|
||||
act->setCustomBackendActionEvent(kActionNextScaleFilter);
|
||||
keymap->addAction(act);
|
||||
|
||||
act = new Action("FLTP", _("Switch to the previous scaler"));
|
||||
act->addDefaultInputMapping("C+A+9");
|
||||
act->setCustomBackendActionEvent(kActionPreviousScaleFilter);
|
||||
keymap->addAction(act);
|
||||
}
|
||||
|
||||
return keymap;
|
||||
}
|
||||
|
||||
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
void SdlGraphicsManager::setImGuiCallbacks(const ImGuiCallbacks &callbacks) {
|
||||
if (_imGuiInited) {
|
||||
if (_imGuiCallbacks.cleanup) {
|
||||
_imGuiCallbacks.cleanup();
|
||||
}
|
||||
_imGuiInited = false;
|
||||
}
|
||||
|
||||
_imGuiCallbacks = callbacks;
|
||||
|
||||
if (!_imGuiReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_imGuiCallbacks.init) {
|
||||
_imGuiCallbacks.init();
|
||||
}
|
||||
_imGuiInited = true;
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::initImGui(SDL_Renderer *renderer, void *glContext) {
|
||||
assert(!_imGuiReady);
|
||||
_imGuiInited = false;
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
if (!ImGui::CreateContext()) {
|
||||
return;
|
||||
}
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
ImGui::StyleColorsDark();
|
||||
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style.WindowRounding = 0.0f;
|
||||
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
||||
io.IniFilename = nullptr;
|
||||
|
||||
_imGuiSDLRenderer = nullptr;
|
||||
#ifdef USE_OPENGL
|
||||
if (!_imGuiReady && glContext) {
|
||||
// Only OpenGL and GLES2 are supported, not GLES
|
||||
if ((OpenGLContext.type != OpenGL::kContextGL) &&
|
||||
(OpenGLContext.type != OpenGL::kContextGLES2)) {
|
||||
ImGui::DestroyContext();
|
||||
return;
|
||||
}
|
||||
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
if (!ImGui_ImplSDL3_InitForOpenGL(_window->getSDLWindow(), glContext)) {
|
||||
#else
|
||||
if (!ImGui_ImplSDL2_InitForOpenGL(_window->getSDLWindow(), glContext)) {
|
||||
#endif
|
||||
ImGui::DestroyContext();
|
||||
return;
|
||||
}
|
||||
|
||||
const char *glslVersion;
|
||||
if (OpenGLContext.type == OpenGL::kContextGLES2) {
|
||||
glslVersion = "#version 100";
|
||||
} else {
|
||||
glslVersion = "#version 110";
|
||||
}
|
||||
if (!ImGui_ImplOpenGL3_Init(glslVersion)) {
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
#else
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
#endif
|
||||
ImGui::DestroyContext();
|
||||
return;
|
||||
}
|
||||
|
||||
_imGuiReady = true;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_IMGUI_SDLRENDERER3
|
||||
if (!_imGuiReady && renderer) {
|
||||
if (!ImGui_ImplSDL3_InitForSDLRenderer(_window->getSDLWindow(), renderer)) {
|
||||
ImGui::DestroyContext();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ImGui_ImplSDLRenderer3_Init(renderer)) {
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
return;
|
||||
}
|
||||
|
||||
_imGuiReady = true;
|
||||
_imGuiSDLRenderer = renderer;
|
||||
}
|
||||
#elif defined(USE_IMGUI_SDLRENDERER2)
|
||||
if (!_imGuiReady && renderer) {
|
||||
if (!ImGui_ImplSDL2_InitForSDLRenderer(_window->getSDLWindow(), renderer)) {
|
||||
ImGui::DestroyContext();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ImGui_ImplSDLRenderer2_Init(renderer)) {
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
return;
|
||||
}
|
||||
|
||||
_imGuiReady = true;
|
||||
_imGuiSDLRenderer = renderer;
|
||||
}
|
||||
#endif
|
||||
if (!_imGuiReady) {
|
||||
warning("No ImGui renderer has been found");
|
||||
ImGui::DestroyContext();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_imGuiCallbacks.init) {
|
||||
_imGuiCallbacks.init();
|
||||
}
|
||||
_imGuiInited = true;
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::renderImGui() {
|
||||
if (!_imGuiReady || !_imGuiCallbacks.render) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_imGuiInited) {
|
||||
if (_imGuiCallbacks.init) {
|
||||
_imGuiCallbacks.init();
|
||||
}
|
||||
_imGuiInited = true;
|
||||
}
|
||||
|
||||
#ifdef USE_IMGUI_SDLRENDERER3
|
||||
if (_imGuiSDLRenderer) {
|
||||
ImGui_ImplSDLRenderer3_NewFrame();
|
||||
} else {
|
||||
#elif defined(USE_IMGUI_SDLRENDERER2)
|
||||
if (_imGuiSDLRenderer) {
|
||||
ImGui_ImplSDLRenderer2_NewFrame();
|
||||
} else {
|
||||
#endif
|
||||
#ifdef USE_OPENGL
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
#endif
|
||||
#if defined(USE_IMGUI_SDLRENDERER2) || defined(USE_IMGUI_SDLRENDERER3)
|
||||
}
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
ImGui_ImplSDL3_NewFrame();
|
||||
#else
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
#endif
|
||||
|
||||
ImGui::NewFrame();
|
||||
_imGuiCallbacks.render();
|
||||
ImGui::Render();
|
||||
#ifdef USE_IMGUI_SDLRENDERER3
|
||||
if (_imGuiSDLRenderer) {
|
||||
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), _imGuiSDLRenderer);
|
||||
} else {
|
||||
#elif defined(USE_IMGUI_SDLRENDERER2)
|
||||
if (_imGuiSDLRenderer) {
|
||||
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), _imGuiSDLRenderer);
|
||||
} else {
|
||||
#endif
|
||||
#ifdef USE_OPENGL
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
|
||||
SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
|
||||
ImGui::UpdatePlatformWindows();
|
||||
ImGui::RenderPlatformWindowsDefault();
|
||||
SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
|
||||
#endif
|
||||
#if defined(USE_IMGUI_SDLRENDERER2) || defined(USE_IMGUI_SDLRENDERER3)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SdlGraphicsManager::destroyImGui() {
|
||||
if (!_imGuiReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_imGuiCallbacks.cleanup) {
|
||||
_imGuiCallbacks.cleanup();
|
||||
}
|
||||
|
||||
_imGuiInited = false;
|
||||
_imGuiReady = false;
|
||||
|
||||
#ifdef USE_IMGUI_SDLRENDERER3
|
||||
if (_imGuiSDLRenderer) {
|
||||
ImGui_ImplSDLRenderer3_Shutdown();
|
||||
} else {
|
||||
#elif defined(USE_IMGUI_SDLRENDERER2)
|
||||
if (_imGuiSDLRenderer) {
|
||||
ImGui_ImplSDLRenderer2_Shutdown();
|
||||
} else {
|
||||
#endif
|
||||
#ifdef USE_OPENGL
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
#endif
|
||||
#if defined(USE_IMGUI_SDLRENDERER2) || defined(USE_IMGUI_SDLRENDERER3)
|
||||
}
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
#else
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
#endif
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
#endif
|
||||
241
backends/graphics/sdl/sdl-graphics.h
Normal file
241
backends/graphics/sdl/sdl-graphics.h
Normal file
@@ -0,0 +1,241 @@
|
||||
/* 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 BACKENDS_GRAPHICS_SDL_SDLGRAPHICS_H
|
||||
#define BACKENDS_GRAPHICS_SDL_SDLGRAPHICS_H
|
||||
|
||||
#include "backends/graphics/windowed.h"
|
||||
#include "backends/platform/sdl/sdl-window.h"
|
||||
|
||||
#include "common/events.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
class SdlEventSource;
|
||||
|
||||
#define USE_OSD 1
|
||||
|
||||
/**
|
||||
* Base class for a SDL based graphics manager.
|
||||
*/
|
||||
class SdlGraphicsManager : virtual public WindowedGraphicsManager, public Common::EventObserver {
|
||||
public:
|
||||
SdlGraphicsManager(SdlEventSource *source, SdlWindow *window);
|
||||
virtual ~SdlGraphicsManager() {}
|
||||
|
||||
/**
|
||||
* Makes this graphics manager active. That means it should be ready to
|
||||
* process inputs now. However, even without being active it should be
|
||||
* able to query the supported modes and other bits.
|
||||
*/
|
||||
virtual void activateManager();
|
||||
|
||||
/**
|
||||
* Makes this graphics manager inactive. This should allow another
|
||||
* graphics manager to become active again.
|
||||
*/
|
||||
virtual void deactivateManager();
|
||||
|
||||
/**
|
||||
* Notify the graphics manager that the graphics needs to be redrawn, since
|
||||
* the application window was modified.
|
||||
*
|
||||
* This is basically called when SDL_VIDEOEXPOSE was received.
|
||||
*/
|
||||
virtual void notifyVideoExpose() = 0;
|
||||
|
||||
/**
|
||||
* Notify the graphics manager about a resize event.
|
||||
*
|
||||
* It is noteworthy that the requested width/height should actually be set
|
||||
* up as is and not changed by the graphics manager, since otherwise it may
|
||||
* lead to odd behavior for certain window managers.
|
||||
*
|
||||
* It is only required to overwrite this method in case you want a
|
||||
* resizable window. The default implementation just does nothing.
|
||||
*
|
||||
* @param width Requested window width.
|
||||
* @param height Requested window height.
|
||||
*/
|
||||
virtual void notifyResize(const int width, const int height) {}
|
||||
|
||||
/**
|
||||
* Notifies the graphics manager about a mouse position change.
|
||||
*
|
||||
* The passed point *must* be converted from window coordinates to virtual
|
||||
* coordinates in order for the event to be processed correctly by the game
|
||||
* engine. Just use `convertWindowToVirtual` for this unless you need to do
|
||||
* something special.
|
||||
*
|
||||
* @param mouse The mouse position in window coordinates, which must be
|
||||
* converted synchronously to virtual coordinates.
|
||||
* @returns true if the mouse was in a valid position for the game and
|
||||
* should cause the event to be sent to the game.
|
||||
*/
|
||||
virtual bool notifyMousePosition(Common::Point &mouse);
|
||||
|
||||
virtual bool showMouse(bool visible) override;
|
||||
bool lockMouse(bool lock) override;
|
||||
|
||||
virtual bool saveScreenshot(const Common::Path &filename) const { return false; }
|
||||
void saveScreenshot() override;
|
||||
|
||||
bool setRotationMode(Common::RotationMode rotation) override { _rotationMode = rotation; return true; }
|
||||
|
||||
// Override from Common::EventObserver
|
||||
bool notifyEvent(const Common::Event &event) override;
|
||||
|
||||
/**
|
||||
* A (subset) of the graphic manager's state. This is used when switching
|
||||
* between different SDL graphic managers at runtime.
|
||||
*/
|
||||
struct State {
|
||||
int screenWidth, screenHeight;
|
||||
bool aspectRatio;
|
||||
bool fullscreen;
|
||||
bool cursorPalette;
|
||||
bool vsync;
|
||||
Common::RotationMode rotation;
|
||||
|
||||
#ifdef USE_RGB_COLOR
|
||||
Graphics::PixelFormat pixelFormat;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the current state of the graphics manager.
|
||||
*/
|
||||
State getState() const;
|
||||
|
||||
/**
|
||||
* Sets up a basic state of the graphics manager.
|
||||
*/
|
||||
bool setState(const State &state);
|
||||
|
||||
/**
|
||||
* @returns the SDL window.
|
||||
*/
|
||||
SdlWindow *getWindow() const { return _window; }
|
||||
|
||||
void initSizeHint(const Graphics::ModeList &modes) override;
|
||||
|
||||
Common::Keymap *getKeymap();
|
||||
|
||||
protected:
|
||||
enum CustomEventAction {
|
||||
kActionToggleFullscreen = 100,
|
||||
kActionToggleMouseCapture,
|
||||
kActionToggleResizableWindow,
|
||||
kActionSaveScreenshot,
|
||||
kActionToggleAspectRatioCorrection,
|
||||
kActionToggleFilteredScaling,
|
||||
kActionCycleStretchMode,
|
||||
kActionIncreaseScaleFactor,
|
||||
kActionDecreaseScaleFactor,
|
||||
kActionNextScaleFilter,
|
||||
kActionPreviousScaleFilter
|
||||
};
|
||||
|
||||
/** Obtain the user configured fullscreen resolution, or default to the desktop resolution */
|
||||
Common::Rect getPreferredFullscreenResolution();
|
||||
|
||||
bool defaultGraphicsModeConfig() const;
|
||||
|
||||
/**
|
||||
* Gets the dimensions of the window directly from SDL instead of from the
|
||||
* values stored by the graphics manager.
|
||||
*/
|
||||
void getWindowSizeFromSdl(int *width, int *height) const {
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
assert(_window);
|
||||
SDL_GetWindowSizeInPixels(_window->getSDLWindow(), width, height);
|
||||
#elif SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
assert(_window);
|
||||
SDL_GL_GetDrawableSize(_window->getSDLWindow(), width, height);
|
||||
#else
|
||||
assert(_hwScreen);
|
||||
|
||||
if (width) {
|
||||
*width = _hwScreen->w;
|
||||
}
|
||||
|
||||
if (height) {
|
||||
*height = _hwScreen->h;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void showSystemMouseCursor(bool visible);
|
||||
|
||||
void setSystemMousePosition(const int x, const int y) override;
|
||||
|
||||
void notifyActiveAreaChanged() override;
|
||||
|
||||
void handleResizeImpl(const int width, const int height) override;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
public:
|
||||
void unlockWindowSize() {
|
||||
_allowWindowSizeReset = true;
|
||||
_hintedWidth = 0;
|
||||
_hintedHeight = 0;
|
||||
}
|
||||
|
||||
// Called by SdlWindow when the window is about to be destroyed
|
||||
virtual void destroyingWindow() {}
|
||||
|
||||
protected:
|
||||
Uint32 _lastFlags;
|
||||
bool _allowWindowSizeReset;
|
||||
int _hintedWidth, _hintedHeight;
|
||||
|
||||
bool createOrUpdateWindow(const int width, const int height, const Uint32 flags);
|
||||
#endif
|
||||
|
||||
SDL_Surface *_hwScreen;
|
||||
SdlEventSource *_eventSource;
|
||||
SdlWindow *_window;
|
||||
|
||||
/**
|
||||
* @returns whether switching the fullscreen state is currently safe
|
||||
*/
|
||||
virtual bool canSwitchFullscreen() const { return false; }
|
||||
|
||||
private:
|
||||
void toggleFullScreen();
|
||||
|
||||
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
public:
|
||||
void setImGuiCallbacks(const ImGuiCallbacks &callbacks) override;
|
||||
|
||||
protected:
|
||||
ImGuiCallbacks _imGuiCallbacks;
|
||||
bool _imGuiReady = false;
|
||||
bool _imGuiInited = false;
|
||||
SDL_Renderer *_imGuiSDLRenderer = nullptr;
|
||||
|
||||
void initImGui(SDL_Renderer *renderer, void *glContext);
|
||||
void renderImGui();
|
||||
void destroyImGui();
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
3298
backends/graphics/surfacesdl/surfacesdl-graphics.cpp
Normal file
3298
backends/graphics/surfacesdl/surfacesdl-graphics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
496
backends/graphics/surfacesdl/surfacesdl-graphics.h
Normal file
496
backends/graphics/surfacesdl/surfacesdl-graphics.h
Normal file
@@ -0,0 +1,496 @@
|
||||
/* 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 BACKENDS_GRAPHICS_SURFACESDL_GRAPHICS_H
|
||||
#define BACKENDS_GRAPHICS_SURFACESDL_GRAPHICS_H
|
||||
|
||||
#include "backends/graphics/graphics.h"
|
||||
#include "backends/graphics/sdl/sdl-graphics.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/scaler.h"
|
||||
#include "graphics/scalerplugin.h"
|
||||
#include "common/events.h"
|
||||
#include "common/mutex.h"
|
||||
|
||||
#include "backends/events/sdl/sdl-events.h"
|
||||
|
||||
#include "backends/platform/sdl/sdl-sys.h"
|
||||
|
||||
#ifndef RELEASE_BUILD
|
||||
// Define this to allow for focus rectangle debugging
|
||||
#define USE_SDL_DEBUG_FOCUSRECT
|
||||
#endif
|
||||
|
||||
enum {
|
||||
GFX_SURFACESDL = 0
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* SDL graphics manager
|
||||
*/
|
||||
class SurfaceSdlGraphicsManager : public SdlGraphicsManager {
|
||||
public:
|
||||
SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window);
|
||||
virtual ~SurfaceSdlGraphicsManager();
|
||||
|
||||
bool hasFeature(OSystem::Feature f) const override;
|
||||
void setFeatureState(OSystem::Feature f, bool enable) override;
|
||||
bool getFeatureState(OSystem::Feature f) const override;
|
||||
|
||||
const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
|
||||
int getDefaultGraphicsMode() const override;
|
||||
bool setGraphicsMode(int mode, uint flags = OSystem::kGfxModeNoFlags) override;
|
||||
int getGraphicsMode() const override;
|
||||
uint getDefaultScaler() const override;
|
||||
uint getDefaultScaleFactor() const override;
|
||||
bool setScaler(uint mode, int factor) override;
|
||||
uint getScaler() const override;
|
||||
uint getScaleFactor() const override;
|
||||
#ifdef USE_RGB_COLOR
|
||||
Graphics::PixelFormat getScreenFormat() const override { return _screenFormat; }
|
||||
Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
const OSystem::GraphicsMode *getSupportedStretchModes() const override;
|
||||
int getDefaultStretchMode() const override;
|
||||
bool setStretchMode(int mode) override;
|
||||
int getStretchMode() const override;
|
||||
#endif
|
||||
void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL) override;
|
||||
int getScreenChangeID() const override { return _screenChangeCount; }
|
||||
|
||||
void beginGFXTransaction() override;
|
||||
OSystem::TransactionError endGFXTransaction() override;
|
||||
|
||||
int16 getHeight() const override;
|
||||
int16 getWidth() const override;
|
||||
|
||||
protected:
|
||||
// PaletteManager API
|
||||
void setPalette(const byte *colors, uint start, uint num) override;
|
||||
void grabPalette(byte *colors, uint start, uint num) const override;
|
||||
virtual void initGraphicsSurface();
|
||||
|
||||
/**
|
||||
* Convert from the SDL pixel format to Graphics::PixelFormat
|
||||
* @param in The SDL pixel format to convert
|
||||
* @param out A pixel format to be written to
|
||||
*/
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
Graphics::PixelFormat convertSDLPixelFormat(SDL_PixelFormat in) const;
|
||||
#else
|
||||
Graphics::PixelFormat convertSDLPixelFormat(SDL_PixelFormat *in) const;
|
||||
#endif
|
||||
public:
|
||||
void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override;
|
||||
Graphics::Surface *lockScreen() override;
|
||||
void unlockScreen() override;
|
||||
void fillScreen(uint32 col) override;
|
||||
void fillScreen(const Common::Rect &r, uint32 col) override;
|
||||
void updateScreen() override;
|
||||
void setFocusRectangle(const Common::Rect& rect) override;
|
||||
void clearFocusRectangle() override;
|
||||
|
||||
Graphics::PixelFormat getOverlayFormat() const override { return _overlayFormat; }
|
||||
void clearOverlay() override;
|
||||
void grabOverlay(Graphics::Surface &surface) const override;
|
||||
void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
|
||||
int16 getOverlayHeight() const override { return _videoMode.overlayHeight; }
|
||||
int16 getOverlayWidth() const override { return _videoMode.overlayWidth; }
|
||||
|
||||
void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override;
|
||||
void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format, const byte *mask, bool disableKeyColor);
|
||||
void setCursorPalette(const byte *colors, uint start, uint num) override;
|
||||
|
||||
#ifdef USE_OSD
|
||||
void displayMessageOnOSD(const Common::U32String &msg) override;
|
||||
void displayActivityIconOnOSD(const Graphics::Surface *icon) override;
|
||||
#endif
|
||||
|
||||
// Override from Common::EventObserver
|
||||
bool notifyEvent(const Common::Event &event) override;
|
||||
|
||||
// SdlGraphicsManager interface
|
||||
void notifyVideoExpose() override;
|
||||
void notifyResize(const int width, const int height) override;
|
||||
|
||||
#if defined(USE_IMGUI) && (defined(USE_IMGUI_SDLRENDERER2) || defined(USE_IMGUI_SDLRENDERER3))
|
||||
void *getImGuiTexture(const Graphics::Surface &image, const byte *palette, int palCount) override;
|
||||
void freeImGuiTexture(void *texture) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifdef USE_OSD
|
||||
/** Surface containing the OSD message */
|
||||
SDL_Surface *_osdMessageSurface;
|
||||
/** Transparency level of the OSD message */
|
||||
uint8 _osdMessageAlpha;
|
||||
/** When to start the fade out */
|
||||
uint32 _osdMessageFadeStartTime;
|
||||
/** Enum with OSD options */
|
||||
enum {
|
||||
kOSDFadeOutDelay = 2 * 1000, /** < Delay before the OSD is faded out (in milliseconds) */
|
||||
kOSDFadeOutDuration = 500, /** < Duration of the OSD fade out (in milliseconds) */
|
||||
kOSDInitialAlpha = 80 /** < Initial alpha level, in percent */
|
||||
};
|
||||
/** Screen rectangle where the OSD message is drawn */
|
||||
SDL_Rect getOSDMessageRect() const;
|
||||
/** Clear the currently displayed OSD message if any */
|
||||
void removeOSDMessage();
|
||||
/** Surface containing the OSD background activity icon */
|
||||
SDL_Surface *_osdIconSurface;
|
||||
/** Screen rectangle where the OSD background activity icon is drawn */
|
||||
SDL_Rect getOSDIconRect() const;
|
||||
|
||||
void updateOSD();
|
||||
void drawOSD();
|
||||
#endif
|
||||
|
||||
class AspectRatio {
|
||||
int _kw, _kh;
|
||||
public:
|
||||
AspectRatio() { _kw = _kh = 0; }
|
||||
AspectRatio(int w, int h);
|
||||
|
||||
bool isAuto() const { return (_kw | _kh) == 0; }
|
||||
|
||||
int kw() const { return _kw; }
|
||||
int kh() const { return _kh; }
|
||||
};
|
||||
|
||||
static AspectRatio getDesiredAspectRatio();
|
||||
|
||||
bool gameNeedsAspectRatioCorrection() const override {
|
||||
return _videoMode.aspectRatioCorrection;
|
||||
}
|
||||
int getGameRenderScale() const override {
|
||||
return _videoMode.scaleFactor;
|
||||
}
|
||||
|
||||
void handleResizeImpl(const int width, const int height) override;
|
||||
|
||||
virtual void setupHardwareSize();
|
||||
|
||||
void fixupResolutionForAspectRatio(AspectRatio desiredAspectRatio, int &width, int &height) const;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
/* SDL2 features a different API for 2D graphics. We create a wrapper
|
||||
* around this API to keep the code paths as close as possible. */
|
||||
SDL_Renderer *_renderer;
|
||||
SDL_Texture *_screenTexture;
|
||||
void deinitializeRenderer();
|
||||
void recreateScreenTexture();
|
||||
|
||||
virtual SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags);
|
||||
virtual void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects);
|
||||
int SDL_SetColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors);
|
||||
int SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha);
|
||||
int SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key);
|
||||
#endif
|
||||
|
||||
/** Unseen game screen */
|
||||
SDL_Surface *_screen;
|
||||
Graphics::PixelFormat _screenFormat;
|
||||
Graphics::PixelFormat _cursorFormat;
|
||||
#ifdef USE_RGB_COLOR
|
||||
Common::List<Graphics::PixelFormat> _supportedFormats;
|
||||
|
||||
/**
|
||||
* Update the list of supported pixel formats.
|
||||
* This method is invoked by loadGFXMode().
|
||||
*/
|
||||
void detectSupportedFormats();
|
||||
#endif
|
||||
|
||||
/** Temporary screen (for scalers) */
|
||||
SDL_Surface *_tmpscreen;
|
||||
/** Temporary screen (for scalers) */
|
||||
SDL_Surface *_tmpscreen2;
|
||||
|
||||
SDL_Surface *_overlayscreen;
|
||||
bool _useOldSrc;
|
||||
Graphics::PixelFormat _overlayFormat;
|
||||
bool _isDoubleBuf, _isHwPalette;
|
||||
|
||||
enum {
|
||||
kTransactionNone = 0,
|
||||
kTransactionActive = 1,
|
||||
kTransactionRollback = 2
|
||||
};
|
||||
|
||||
struct TransactionDetails {
|
||||
bool sizeChanged;
|
||||
bool needHotswap;
|
||||
bool needUpdatescreen;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
bool needTextureUpdate;
|
||||
bool needDisplayResize;
|
||||
#endif
|
||||
#ifdef USE_RGB_COLOR
|
||||
bool formatChanged;
|
||||
#endif
|
||||
|
||||
TransactionDetails() {
|
||||
sizeChanged = false;
|
||||
needHotswap = false;
|
||||
needUpdatescreen = false;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
needTextureUpdate = false;
|
||||
needDisplayResize = false;
|
||||
#endif
|
||||
#ifdef USE_RGB_COLOR
|
||||
formatChanged = false;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
TransactionDetails _transactionDetails;
|
||||
|
||||
struct VideoState {
|
||||
bool setup;
|
||||
|
||||
bool fullscreen;
|
||||
bool aspectRatioCorrection;
|
||||
AspectRatio desiredAspectRatio;
|
||||
bool filtering;
|
||||
|
||||
int mode;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
int stretchMode;
|
||||
#endif
|
||||
bool vsync;
|
||||
|
||||
uint scalerIndex;
|
||||
int scaleFactor;
|
||||
|
||||
int screenWidth, screenHeight;
|
||||
int overlayWidth, overlayHeight;
|
||||
int hardwareWidth, hardwareHeight;
|
||||
#ifdef USE_RGB_COLOR
|
||||
Graphics::PixelFormat format;
|
||||
#endif
|
||||
|
||||
VideoState() {
|
||||
setup = false;
|
||||
fullscreen = false;
|
||||
aspectRatioCorrection = false;
|
||||
// desiredAspectRatio set to (0, 0) by AspectRatio constructor
|
||||
filtering = false;
|
||||
|
||||
mode = GFX_SURFACESDL;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
stretchMode = 0;
|
||||
#endif
|
||||
vsync = false;
|
||||
|
||||
scalerIndex = 0;
|
||||
scaleFactor = 0;
|
||||
|
||||
screenWidth = 0;
|
||||
screenHeight = 0;
|
||||
overlayWidth = 0;
|
||||
overlayHeight = 0;
|
||||
hardwareWidth = 0;
|
||||
hardwareHeight = 0;
|
||||
#ifdef USE_RGB_COLOR
|
||||
// format set to 0 values by Graphics::PixelFormat constructor
|
||||
#endif
|
||||
}
|
||||
};
|
||||
VideoState _videoMode, _oldVideoMode;
|
||||
|
||||
#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
/**
|
||||
* Original BPP to restore the video mode on unload.
|
||||
*
|
||||
* This is required to make listing video modes for the OpenGL output work
|
||||
* on Windows 8+. On these systems OpenGL modes are only available for
|
||||
* 32bit formats. However, we setup a 16bit format and thus mode listings
|
||||
* for OpenGL will return an empty list afterwards.
|
||||
*
|
||||
* In theory we might require this behavior on non-Win32 platforms too.
|
||||
* However, SDL sometimes gives us invalid pixel formats for X11 outputs
|
||||
* causing crashes when trying to setup the original pixel format.
|
||||
* See bug #7038 "IRIX: X BadMatch when trying to start any 640x480 game".
|
||||
*/
|
||||
uint8 _originalBitsPerPixel;
|
||||
#endif
|
||||
|
||||
int _transactionMode;
|
||||
|
||||
// Indicates whether it is needed to free _hwSurface in destructor
|
||||
bool _displayDisabled;
|
||||
|
||||
const PluginList &_scalerPlugins;
|
||||
ScalerPluginObject *_scalerPlugin;
|
||||
Scaler *_scaler, *_mouseScaler;
|
||||
uint _maxExtraPixels;
|
||||
uint _extraPixels;
|
||||
|
||||
bool _screenIsLocked;
|
||||
Graphics::Surface _framebuffer;
|
||||
|
||||
int _screenChangeCount;
|
||||
|
||||
enum {
|
||||
NUM_DIRTY_RECT = 100,
|
||||
MAX_SCALING = 3
|
||||
};
|
||||
|
||||
// Dirty rect management
|
||||
// When double-buffering we need to redraw both updates from
|
||||
// current frame and previous frame. For convenience we copy
|
||||
// them here before traversing the list.
|
||||
SDL_Rect _dirtyRectList[2 * NUM_DIRTY_RECT];
|
||||
int _numDirtyRects;
|
||||
|
||||
SDL_Rect _prevDirtyRectList[NUM_DIRTY_RECT];
|
||||
int _numPrevDirtyRects;
|
||||
|
||||
struct MousePos {
|
||||
// The size and hotspot of the original cursor image.
|
||||
int16 w, h;
|
||||
int16 hotX, hotY;
|
||||
|
||||
// The size and hotspot of the pre-scaled cursor image, in real
|
||||
// coordinates.
|
||||
int16 rW, rH;
|
||||
int16 rHotX, rHotY;
|
||||
|
||||
// The size and hotspot of the pre-scaled cursor image, in game
|
||||
// coordinates.
|
||||
int16 vW, vH;
|
||||
int16 vHotX, vHotY;
|
||||
|
||||
MousePos() : w(0), h(0), hotX(0), hotY(0),
|
||||
rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0),
|
||||
vHotX(0), vHotY(0)
|
||||
{ }
|
||||
};
|
||||
|
||||
SDL_Rect _mouseLastRect, _mouseNextRect;
|
||||
MousePos _mouseCurState;
|
||||
#ifdef USE_RGB_COLOR
|
||||
uint32 _mouseKeyColor;
|
||||
#else
|
||||
byte _mouseKeyColor;
|
||||
#endif
|
||||
bool _disableMouseKeyColor;
|
||||
byte _mappedMouseKeyColor;
|
||||
bool _cursorDontScale;
|
||||
bool _cursorPaletteDisabled;
|
||||
SDL_Surface *_mouseOrigSurface;
|
||||
SDL_Surface *_mouseSurface;
|
||||
|
||||
// Shake mode
|
||||
// This is always set to 0 when building with SDL2.
|
||||
int _currentShakeXOffset;
|
||||
int _currentShakeYOffset;
|
||||
|
||||
// Palette data
|
||||
SDL_Color *_currentPalette;
|
||||
uint _paletteDirtyStart, _paletteDirtyEnd;
|
||||
|
||||
SDL_Color *_overlayPalette;
|
||||
bool _isInOverlayPalette;
|
||||
|
||||
// Cursor palette data
|
||||
SDL_Color *_cursorPalette;
|
||||
|
||||
/**
|
||||
* Mutex which prevents multiple threads from interfering with each other
|
||||
* when accessing the screen.
|
||||
*/
|
||||
Common::Mutex _graphicsMutex;
|
||||
|
||||
#ifdef USE_SDL_DEBUG_FOCUSRECT
|
||||
bool _enableFocusRectDebugCode;
|
||||
bool _enableFocusRect;
|
||||
Common::Rect _focusRect;
|
||||
#endif
|
||||
|
||||
virtual void addDirtyRect(int x, int y, int w, int h, bool inOverlay, bool realCoordinates = false);
|
||||
|
||||
virtual void drawMouse();
|
||||
virtual void undrawMouse();
|
||||
virtual void blitCursor();
|
||||
|
||||
virtual void internUpdateScreen();
|
||||
virtual void updateScreen(SDL_Rect *dirtyRectList, int actualDirtyRects);
|
||||
|
||||
virtual bool loadGFXMode();
|
||||
virtual void unloadGFXMode();
|
||||
virtual bool hotswapGFXMode();
|
||||
|
||||
virtual void setAspectRatioCorrection(bool enable);
|
||||
void setFilteringMode(bool enable);
|
||||
void setVSync(bool enable);
|
||||
|
||||
bool saveScreenshot(const Common::Path &filename) const override;
|
||||
virtual void setGraphicsModeIntern();
|
||||
virtual void getDefaultResolution(uint &w, uint &h);
|
||||
|
||||
// In SurfaceSDL mode we never render in 3D and can always switch the fullscreen state
|
||||
bool canSwitchFullscreen() const override { return true; }
|
||||
|
||||
private:
|
||||
void setFullscreenMode(bool enable);
|
||||
void handleScalerHotkeys(uint mode, int factor);
|
||||
|
||||
/**
|
||||
* Converts the given point from the overlay's coordinate space to the
|
||||
* game's coordinate space.
|
||||
*/
|
||||
Common::Point convertOverlayToGame(const int x, const int y) const {
|
||||
if (getOverlayWidth() == 0 || getOverlayHeight() == 0) {
|
||||
error("convertOverlayToGame called without a valid overlay");
|
||||
}
|
||||
|
||||
return Common::Point(x * getWidth() / getOverlayWidth(),
|
||||
y * getHeight() / getOverlayHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given point from the game's coordinate space to the
|
||||
* overlay's coordinate space.
|
||||
*/
|
||||
Common::Point convertGameToOverlay(const int x, const int y) const {
|
||||
if (getWidth() == 0 || getHeight() == 0) {
|
||||
error("convertGameToOverlay called without a valid overlay");
|
||||
}
|
||||
|
||||
return Common::Point(x * getOverlayWidth() / getWidth(),
|
||||
y * getOverlayHeight() / getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Special case for scalers that use the useOldSrc feature (currently
|
||||
* only the Edge scalers). The variable is checked after closing the
|
||||
* overlay, so that the creation of a new output buffer for the scaler
|
||||
* can be triggered.
|
||||
*/
|
||||
bool _needRestoreAfterOverlay;
|
||||
bool _prevForceRedraw;
|
||||
bool _prevCursorNeedsRedraw;
|
||||
};
|
||||
|
||||
#endif
|
||||
689
backends/graphics/windowed.h
Normal file
689
backends/graphics/windowed.h
Normal file
@@ -0,0 +1,689 @@
|
||||
/* 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 BACKENDS_GRAPHICS_WINDOWED_H
|
||||
#define BACKENDS_GRAPHICS_WINDOWED_H
|
||||
|
||||
#include "backends/graphics/graphics.h"
|
||||
#include "common/frac.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/scaler/aspect.h"
|
||||
|
||||
enum {
|
||||
STRETCH_CENTER = 0,
|
||||
STRETCH_INTEGRAL = 1,
|
||||
STRETCH_INTEGRAL_AR = 2,
|
||||
STRETCH_FIT = 3,
|
||||
STRETCH_STRETCH = 4,
|
||||
STRETCH_FIT_FORCE_ASPECT = 5
|
||||
};
|
||||
|
||||
enum {
|
||||
SCREEN_ALIGN_CENTER = 0,
|
||||
SCREEN_ALIGN_LEFT = 1,
|
||||
SCREEN_ALIGN_RIGHT = 2,
|
||||
SCREEN_ALIGN_XMASK = 3,
|
||||
SCREEN_ALIGN_MIDDLE = 0,
|
||||
SCREEN_ALIGN_TOP = 4,
|
||||
SCREEN_ALIGN_BOTTOM = 8,
|
||||
SCREEN_ALIGN_YMASK = 12
|
||||
};
|
||||
|
||||
class WindowedGraphicsManager : virtual public GraphicsManager {
|
||||
public:
|
||||
WindowedGraphicsManager() :
|
||||
_windowWidth(0),
|
||||
_windowHeight(0),
|
||||
_screenAlign(SCREEN_ALIGN_CENTER | SCREEN_ALIGN_MIDDLE),
|
||||
_rotationMode(Common::kRotationNormal),
|
||||
_ignoreGameSafeArea(false),
|
||||
_overlayVisible(false),
|
||||
_overlayInGUI(false),
|
||||
_gameScreenShakeXOffset(0),
|
||||
_gameScreenShakeYOffset(0),
|
||||
_forceRedraw(false),
|
||||
_cursorVisible(false),
|
||||
_cursorX(0),
|
||||
_cursorY(0),
|
||||
_cursorNeedsRedraw(false),
|
||||
_cursorLastInActiveArea(true) {}
|
||||
|
||||
void showOverlay(bool inGUI) override {
|
||||
_overlayInGUI = inGUI;
|
||||
|
||||
if (inGUI) {
|
||||
_activeArea.drawRect = _overlayDrawRect;
|
||||
_activeArea.width = getOverlayWidth();
|
||||
_activeArea.height = getOverlayHeight();
|
||||
} else {
|
||||
_activeArea.drawRect = _gameDrawRect;
|
||||
_activeArea.width = getWidth();
|
||||
_activeArea.height = getHeight();
|
||||
}
|
||||
|
||||
if (_overlayVisible)
|
||||
return;
|
||||
|
||||
_overlayVisible = true;
|
||||
_forceRedraw = true;
|
||||
notifyActiveAreaChanged();
|
||||
}
|
||||
|
||||
void hideOverlay() override {
|
||||
if (!_overlayVisible)
|
||||
return;
|
||||
|
||||
_overlayInGUI = false;
|
||||
|
||||
_activeArea.drawRect = _gameDrawRect;
|
||||
_activeArea.width = getWidth();
|
||||
_activeArea.height = getHeight();
|
||||
_overlayVisible = false;
|
||||
_forceRedraw = true;
|
||||
notifyActiveAreaChanged();
|
||||
}
|
||||
|
||||
bool isOverlayVisible() const override { return _overlayVisible; }
|
||||
|
||||
Common::Rect getSafeOverlayArea(int16 *width, int16 *height) const override {
|
||||
Insets insets = getSafeAreaInsets();
|
||||
|
||||
// Create the overlay rect cut of the insets
|
||||
// in the window coordinate space
|
||||
// Make sure to avoid a negative size (and an invalid rect)
|
||||
const int safeLeft = MAX(_overlayDrawRect.left, insets.left),
|
||||
safeTop = MAX(_overlayDrawRect.top, insets.top);
|
||||
Common::Rect safeArea(safeLeft, safeTop,
|
||||
MAX(safeLeft, MIN((int)_overlayDrawRect.right, _windowWidth - insets.right)),
|
||||
MAX(safeTop, MIN((int)_overlayDrawRect.bottom, _windowHeight - insets.bottom)));
|
||||
|
||||
// Convert this safe area in the overlay coordinate space
|
||||
const int targetWidth = getOverlayWidth(),
|
||||
targetHeight = getOverlayHeight(),
|
||||
sourceWidth = _overlayDrawRect.width(),
|
||||
sourceHeight = _overlayDrawRect.height();
|
||||
|
||||
if (width) *width = targetWidth;
|
||||
if (height) *height = targetHeight;
|
||||
|
||||
int rotatedTargetWidth = targetWidth,
|
||||
rotatedTargetHeight = targetHeight;
|
||||
if (_rotationMode == Common::kRotation90 || _rotationMode == Common::kRotation270) {
|
||||
SWAP(rotatedTargetWidth, rotatedTargetHeight);
|
||||
}
|
||||
|
||||
// First make it relative to overlay origin and scale it
|
||||
safeArea.left = ((safeArea.left - _overlayDrawRect.left) * rotatedTargetWidth) / sourceWidth;
|
||||
safeArea.top = ((safeArea.top - _overlayDrawRect.top) * rotatedTargetHeight) / sourceHeight;
|
||||
safeArea.right = ((safeArea.right - _overlayDrawRect.left) * rotatedTargetWidth) / sourceWidth;
|
||||
safeArea.bottom = ((safeArea.bottom - _overlayDrawRect.top) * rotatedTargetHeight) / sourceHeight;
|
||||
|
||||
// Now rotate it
|
||||
switch (_rotationMode) {
|
||||
default:
|
||||
case Common::kRotationNormal:
|
||||
// Nothing to do
|
||||
break;
|
||||
case Common::kRotation90: {
|
||||
int16 tmp = safeArea.left;
|
||||
safeArea.left = safeArea.top;
|
||||
safeArea.top = rotatedTargetWidth - safeArea.right;
|
||||
//safeArea.right = targetWidth - (rotatedTargetHeight - safeArea.bottom);
|
||||
safeArea.right = safeArea.bottom; // targetWidth == rotatedTargetHeight
|
||||
safeArea.bottom = targetHeight - tmp;
|
||||
break;
|
||||
}
|
||||
case Common::kRotation180: {
|
||||
int16 tmp;
|
||||
tmp = safeArea.left;
|
||||
safeArea.left = rotatedTargetWidth - safeArea.right;
|
||||
safeArea.right = rotatedTargetWidth - tmp;
|
||||
tmp = safeArea.top;
|
||||
safeArea.top = rotatedTargetHeight - safeArea.bottom;
|
||||
safeArea.bottom = rotatedTargetHeight - tmp;
|
||||
break;
|
||||
}
|
||||
case Common::kRotation270: {
|
||||
int16 tmp = safeArea.left;
|
||||
safeArea.left = rotatedTargetHeight - safeArea.bottom;
|
||||
//safeArea.bottom = targetHeight - (rotatedTargetWidth - safeArea.right);
|
||||
safeArea.bottom = safeArea.right; // targetHeight == rotatedTargetWidth
|
||||
safeArea.right = targetWidth - safeArea.top;
|
||||
safeArea.top = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return safeArea;
|
||||
}
|
||||
|
||||
void setShakePos(int shakeXOffset, int shakeYOffset) override {
|
||||
if (_gameScreenShakeXOffset != shakeXOffset || _gameScreenShakeYOffset != shakeYOffset) {
|
||||
_gameScreenShakeXOffset = shakeXOffset;
|
||||
_gameScreenShakeYOffset = shakeYOffset;
|
||||
recalculateDisplayAreas();
|
||||
_cursorNeedsRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
int getWindowWidth() const { return _windowWidth; }
|
||||
int getWindowHeight() const { return _windowHeight; }
|
||||
|
||||
void setIgnoreGameSafeArea(bool ignoreGameSafeArea) {
|
||||
if (_ignoreGameSafeArea == ignoreGameSafeArea) {
|
||||
return;
|
||||
}
|
||||
|
||||
_ignoreGameSafeArea = ignoreGameSafeArea;
|
||||
|
||||
Insets insets = getSafeAreaInsets();
|
||||
if (insets.left == 0 &&
|
||||
insets.top == 0 &&
|
||||
insets.right == 0 &&
|
||||
insets.bottom == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleResizeImpl(_windowWidth, _windowHeight);
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @returns whether or not the game screen must have aspect ratio correction
|
||||
* applied for correct rendering.
|
||||
*/
|
||||
virtual bool gameNeedsAspectRatioCorrection() const = 0;
|
||||
|
||||
/**
|
||||
* Backend-specific implementation for updating internal surfaces that need
|
||||
* to reflect the new window size.
|
||||
*/
|
||||
virtual void handleResizeImpl(const int width, const int height) = 0;
|
||||
|
||||
/**
|
||||
* Converts the given point from the active virtual screen's coordinate
|
||||
* space to the window's coordinate space (i.e. game-to-window or
|
||||
* overlay-to-window).
|
||||
*/
|
||||
Common::Point convertVirtualToWindow(const int x, const int y) const {
|
||||
const int targetX = _activeArea.drawRect.left;
|
||||
const int targetY = _activeArea.drawRect.top;
|
||||
const int targetWidth = _activeArea.drawRect.width();
|
||||
const int targetHeight = _activeArea.drawRect.height();
|
||||
const int sourceWidth = _activeArea.width;
|
||||
const int sourceHeight = _activeArea.height;
|
||||
|
||||
if (sourceWidth == 0 || sourceHeight == 0) {
|
||||
error("convertVirtualToWindow called without a valid draw rect");
|
||||
}
|
||||
|
||||
int windowX, windowY;
|
||||
switch (_rotationMode) {
|
||||
default:
|
||||
case Common::kRotationNormal:
|
||||
windowX = targetX + (x * targetWidth + sourceWidth / 2) / sourceWidth;
|
||||
windowY = targetY + (y * targetHeight + sourceHeight / 2) / sourceHeight;
|
||||
break;
|
||||
case Common::kRotation90:
|
||||
windowX = targetX + ((y - (sourceHeight - 1)) * targetWidth + sourceHeight / 2) / sourceHeight;
|
||||
windowY = targetY + (x * targetHeight + sourceWidth / 2) / sourceWidth;
|
||||
break;
|
||||
case Common::kRotation180:
|
||||
windowX = targetX + ((x - (sourceWidth - 1)) * targetWidth + sourceWidth / 2) / sourceWidth;
|
||||
windowY = targetY + ((y - (sourceHeight - 1)) * targetHeight + sourceHeight / 2) / sourceHeight;
|
||||
break;
|
||||
case Common::kRotation270:
|
||||
windowX = targetX + (y * targetWidth + sourceHeight / 2) / sourceHeight;
|
||||
windowY = targetY + ((x - (sourceWidth - 1)) * targetHeight + sourceWidth / 2) / sourceWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
return Common::Point(CLIP<int>(windowX, targetX, targetX + targetWidth - 1),
|
||||
CLIP<int>(windowY, targetY, targetY + targetHeight - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given point from the window's coordinate space to the
|
||||
* active virtual screen's coordinate space (i.e. window-to-game or
|
||||
* window-to-overlay).
|
||||
*/
|
||||
Common::Point convertWindowToVirtual(int x, int y) const {
|
||||
const int sourceX = _activeArea.drawRect.left;
|
||||
const int sourceY = _activeArea.drawRect.top;
|
||||
const int sourceMaxX = _activeArea.drawRect.right - 1;
|
||||
const int sourceMaxY = _activeArea.drawRect.bottom - 1;
|
||||
const int sourceWidth = _activeArea.drawRect.width();
|
||||
const int sourceHeight = _activeArea.drawRect.height();
|
||||
const int targetWidth = _activeArea.width;
|
||||
const int targetHeight = _activeArea.height;
|
||||
|
||||
if (sourceWidth == 0 || sourceHeight == 0) {
|
||||
error("convertWindowToVirtual called without a valid draw rect");
|
||||
}
|
||||
|
||||
x = CLIP<int>(x, sourceX, sourceMaxX);
|
||||
y = CLIP<int>(y, sourceY, sourceMaxY);
|
||||
|
||||
int virtualX, virtualY;
|
||||
switch (_rotationMode) {
|
||||
default:
|
||||
case Common::kRotationNormal:
|
||||
virtualX = ((x - sourceX) * targetWidth + sourceWidth / 2) / sourceWidth;
|
||||
virtualY = ((y - sourceY) * targetHeight + sourceHeight / 2) / sourceHeight;
|
||||
break;
|
||||
case Common::kRotation90:
|
||||
virtualY = targetHeight - 1 - ((x - sourceX) * targetHeight + sourceWidth / 2) / sourceWidth;
|
||||
virtualX = ((y - sourceY) * targetWidth + sourceHeight / 2) / sourceHeight;
|
||||
break;
|
||||
case Common::kRotation180:
|
||||
virtualX = targetWidth - 1 - ((x - sourceX) * targetWidth + sourceWidth / 2) / sourceWidth;
|
||||
virtualY = targetHeight - 1 - ((y - sourceY) * targetHeight + sourceHeight / 2) / sourceHeight;
|
||||
break;
|
||||
case Common::kRotation270:
|
||||
virtualY = ((x - sourceX) * targetHeight + sourceWidth / 2) / sourceWidth;
|
||||
virtualX = targetWidth - 1 - ((y - sourceY) * targetWidth + sourceHeight / 2) / sourceHeight;
|
||||
break;
|
||||
}
|
||||
|
||||
return Common::Point(CLIP<int>(virtualX, 0, targetWidth - 1),
|
||||
CLIP<int>(virtualY, 0, targetHeight - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the desired aspect ratio of the game surface.
|
||||
*/
|
||||
frac_t getDesiredGameAspectRatio() const {
|
||||
if (getHeight() == 0 || gameNeedsAspectRatioCorrection()) {
|
||||
return intToFrac(4) / 3;
|
||||
}
|
||||
|
||||
return intToFrac(getWidth()) / getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the scale used between the game size and the surface on which it is rendered.
|
||||
*/
|
||||
virtual int getGameRenderScale() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct Insets {
|
||||
int16 left;
|
||||
int16 top;
|
||||
int16 right;
|
||||
int16 bottom;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the insets needed to get a safe area which does not interfere
|
||||
* with any system UI elements such as the notch or home indicator on mobile devices.
|
||||
*
|
||||
* @return The safe area insets
|
||||
*/
|
||||
virtual Insets getSafeAreaInsets() const {
|
||||
return {0, 0, 0, 0};
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the window has been updated with new dimensions.
|
||||
*
|
||||
* @param width The new width of the window, excluding window decoration.
|
||||
* @param height The new height of the window, excluding window decoration.
|
||||
*/
|
||||
void handleResize(const int width, const int height) {
|
||||
_windowWidth = width;
|
||||
_windowHeight = height;
|
||||
handleResizeImpl(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculates the display areas for the game and overlay surfaces within
|
||||
* the window.
|
||||
*/
|
||||
virtual void recalculateDisplayAreas() {
|
||||
if (_windowHeight == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute a safe area rectangle out of the insets
|
||||
Insets insets;
|
||||
if (_ignoreGameSafeArea) {
|
||||
insets = {0, 0, 0, 0};
|
||||
} else {
|
||||
insets = getSafeAreaInsets();
|
||||
}
|
||||
Common::Rect safeArea(insets.left, insets.top,
|
||||
_windowWidth - insets.right,
|
||||
_windowHeight - insets.bottom);
|
||||
|
||||
// Create a game draw rect using the safe are dimensions
|
||||
populateDisplayAreaDrawRect(getDesiredGameAspectRatio(),
|
||||
getWidth() * getGameRenderScale(), getHeight() * getGameRenderScale(),
|
||||
safeArea, _gameDrawRect);
|
||||
|
||||
if (getOverlayHeight()) {
|
||||
const int16 overlayWidth = getOverlayWidth(),
|
||||
overlayHeight = getOverlayHeight();
|
||||
const frac_t overlayAspect = intToFrac(overlayWidth) / overlayHeight;
|
||||
populateDisplayAreaDrawRect(overlayAspect, overlayWidth, overlayHeight,
|
||||
Common::Rect(_windowWidth, _windowHeight),_overlayDrawRect);
|
||||
}
|
||||
|
||||
if (_overlayInGUI) {
|
||||
_activeArea.drawRect = _overlayDrawRect;
|
||||
_activeArea.width = getOverlayWidth();
|
||||
_activeArea.height = getOverlayHeight();
|
||||
} else {
|
||||
_activeArea.drawRect = _gameDrawRect;
|
||||
_activeArea.width = getWidth();
|
||||
_activeArea.height = getHeight();
|
||||
}
|
||||
notifyActiveAreaChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the hardware mouse cursor in the host system,
|
||||
* relative to the window.
|
||||
*
|
||||
* @param x X coordinate in window coordinates.
|
||||
* @param y Y coordinate in window coordinates.
|
||||
*/
|
||||
virtual void setSystemMousePosition(const int x, const int y) = 0;
|
||||
|
||||
/**
|
||||
* Called whenever the active area has changed.
|
||||
*/
|
||||
virtual void notifyActiveAreaChanged() {}
|
||||
|
||||
bool showMouse(bool visible) override {
|
||||
if (_cursorVisible == visible) {
|
||||
return visible;
|
||||
}
|
||||
|
||||
const bool last = _cursorVisible;
|
||||
_cursorVisible = visible;
|
||||
_cursorNeedsRedraw = true;
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move ("warp") the mouse cursor to the specified position.
|
||||
*
|
||||
* @param x The new X position of the mouse in virtual screen coordinates.
|
||||
* @param y The new Y position of the mouse in virtual screen coordinates.
|
||||
*/
|
||||
void warpMouse(int x, int y) override {
|
||||
// Check active coordinate instead of window coordinate to avoid warping
|
||||
// the mouse if it is still within the same virtual pixel
|
||||
const Common::Point virtualCursor = convertWindowToVirtual(_cursorX, _cursorY);
|
||||
if (virtualCursor.x != x || virtualCursor.y != y) {
|
||||
// Warping the mouse in SDL generates a mouse movement event, so
|
||||
// `setMousePosition` would be called eventually through the
|
||||
// `notifyMousePosition` callback if we *only* set the system mouse
|
||||
// position here. However, this can cause problems with some games.
|
||||
// For example, the cannon script in CoMI calls to warp the mouse
|
||||
// twice each time the cannon is reloaded, and unless we update the
|
||||
// mouse position immediately, the second call is ignored, which
|
||||
// causes the cannon to change its aim.
|
||||
const Common::Point windowCursor = convertVirtualToWindow(x, y);
|
||||
setMousePosition(windowCursor.x, windowCursor.y);
|
||||
setSystemMousePosition(windowCursor.x, windowCursor.y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the rendered mouse cursor in the window.
|
||||
*
|
||||
* @param x X coordinate in window coordinates.
|
||||
* @param y Y coordinate in window coordinates.
|
||||
*/
|
||||
void setMousePosition(int x, int y) {
|
||||
if (_cursorX != x || _cursorY != y) {
|
||||
_cursorNeedsRedraw = true;
|
||||
}
|
||||
|
||||
_cursorX = x;
|
||||
_cursorY = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* The width of the window, excluding window decoration.
|
||||
*/
|
||||
int _windowWidth;
|
||||
|
||||
/**
|
||||
* The height of the window, excluding window decoration.
|
||||
*/
|
||||
int _windowHeight;
|
||||
|
||||
/**
|
||||
* How the overlay and game screens are aligned in the window.
|
||||
* Centered vertically and horizontally by default.
|
||||
*/
|
||||
int _screenAlign;
|
||||
|
||||
/**
|
||||
* How the screens need to be rotated on the screen
|
||||
*/
|
||||
Common::RotationMode _rotationMode;
|
||||
|
||||
/**
|
||||
* Whether the safe area should be ignored for games
|
||||
*/
|
||||
bool _ignoreGameSafeArea;
|
||||
|
||||
/**
|
||||
* Whether the overlay (i.e. launcher, including the out-of-game launcher)
|
||||
* is visible or not.
|
||||
*/
|
||||
bool _overlayVisible;
|
||||
|
||||
/**
|
||||
* Whether when overlay is shown, mouse coordinates depend on window or game screen size
|
||||
*/
|
||||
bool _overlayInGUI;
|
||||
|
||||
/**
|
||||
* The offset by which the screen is moved horizontally.
|
||||
*/
|
||||
int _gameScreenShakeXOffset;
|
||||
|
||||
/**
|
||||
* The offset by which the screen is moved vertically.
|
||||
*/
|
||||
int _gameScreenShakeYOffset;
|
||||
|
||||
/**
|
||||
* The scaled draw rectangle for the game surface within the window.
|
||||
*/
|
||||
Common::Rect _gameDrawRect;
|
||||
|
||||
/**
|
||||
* The scaled draw rectangle for the overlay (launcher) surface within the
|
||||
* window.
|
||||
*/
|
||||
Common::Rect _overlayDrawRect;
|
||||
|
||||
/**
|
||||
* Data about the display area of a virtual screen.
|
||||
*/
|
||||
struct DisplayArea {
|
||||
/**
|
||||
* The scaled area where the virtual screen is drawn within the window.
|
||||
*/
|
||||
Common::Rect drawRect;
|
||||
|
||||
/**
|
||||
* The width of the virtual screen's unscaled coordinate space.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height of the virtual screen's unscaled coordinate space.
|
||||
*/
|
||||
int height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Display area information about the currently active virtual screen. This
|
||||
* will be the overlay screen when the overlay is active, and the game
|
||||
* screen otherwise.
|
||||
*/
|
||||
DisplayArea _activeArea;
|
||||
|
||||
/**
|
||||
* Whether the screen must be redrawn on the next frame.
|
||||
*/
|
||||
bool _forceRedraw;
|
||||
|
||||
/**
|
||||
* Whether the cursor is actually visible.
|
||||
*/
|
||||
bool _cursorVisible;
|
||||
|
||||
/**
|
||||
* Whether the mouse cursor needs to be redrawn on the next frame.
|
||||
*/
|
||||
bool _cursorNeedsRedraw;
|
||||
|
||||
/**
|
||||
* Whether the last position of the system cursor was within the active area
|
||||
* of the window.
|
||||
*/
|
||||
bool _cursorLastInActiveArea;
|
||||
|
||||
/**
|
||||
* The position of the mouse cursor, in window coordinates.
|
||||
*/
|
||||
int _cursorX, _cursorY;
|
||||
|
||||
private:
|
||||
void populateDisplayAreaDrawRect(const frac_t displayAspect, int originalWidth, int originalHeight, const Common::Rect &safeArea, Common::Rect &drawRect) const {
|
||||
int mode = getStretchMode();
|
||||
|
||||
Common::Rect rotatedSafeArea(safeArea);
|
||||
int rotatedWindowWidth = _windowWidth,
|
||||
rotatedWindowHeight = _windowHeight;
|
||||
|
||||
if (_rotationMode == Common::kRotation90 || _rotationMode == Common::kRotation270) {
|
||||
SWAP(rotatedSafeArea.left, rotatedSafeArea.top);
|
||||
SWAP(rotatedSafeArea.right, rotatedSafeArea.bottom);
|
||||
SWAP(rotatedWindowWidth, rotatedWindowHeight);
|
||||
}
|
||||
const int rotatedSafeWidth = rotatedSafeArea.width(),
|
||||
rotatedSafeHeight = rotatedSafeArea.height();
|
||||
|
||||
// Mode Center = use original size, or divide by an integral amount if window is smaller than game surface
|
||||
// Mode Integral = scale by an integral amount.
|
||||
// Mode Fit = scale to fit the window while respecting the aspect ratio
|
||||
// Mode Stretch = scale and stretch to fit the window without respecting the aspect ratio
|
||||
// Mode Fit Force Aspect = scale to fit the window while forcing a 4:3 aspect ratio
|
||||
int width = 0, height = 0;
|
||||
if (mode == STRETCH_CENTER || mode == STRETCH_INTEGRAL || mode == STRETCH_INTEGRAL_AR) {
|
||||
width = originalWidth;
|
||||
height = intToFrac(width) / displayAspect;
|
||||
if (width > rotatedSafeWidth || height > rotatedSafeHeight) {
|
||||
int fac = 1 + MAX((width - 1) / rotatedSafeWidth, (height - 1) / rotatedSafeHeight);
|
||||
width /= fac;
|
||||
height /= fac;
|
||||
} else if (mode == STRETCH_INTEGRAL) {
|
||||
int fac = MIN(rotatedSafeWidth / width, rotatedSafeHeight / height);
|
||||
width *= fac;
|
||||
height *= fac;
|
||||
} else if (mode == STRETCH_INTEGRAL_AR) {
|
||||
int targetHeight = height;
|
||||
int horizontalFac = rotatedSafeWidth / width;
|
||||
do {
|
||||
width = originalWidth * horizontalFac;
|
||||
int verticalFac = (targetHeight * horizontalFac + originalHeight / 2) / originalHeight;
|
||||
height = originalHeight * verticalFac;
|
||||
--horizontalFac;
|
||||
} while (horizontalFac > 0 && height > rotatedSafeHeight);
|
||||
if (height > rotatedSafeHeight)
|
||||
height = targetHeight;
|
||||
}
|
||||
} else {
|
||||
frac_t windowAspect = intToFrac(rotatedSafeWidth) / rotatedSafeHeight;
|
||||
width = rotatedSafeWidth;
|
||||
height = rotatedSafeHeight;
|
||||
if (mode == STRETCH_FIT_FORCE_ASPECT) {
|
||||
frac_t ratio = intToFrac(4) / 3;
|
||||
if (windowAspect < ratio)
|
||||
height = intToFrac(width) / ratio;
|
||||
else if (windowAspect > ratio)
|
||||
width = fracToInt(height * ratio);
|
||||
} else if (mode != STRETCH_STRETCH) {
|
||||
if (windowAspect < displayAspect)
|
||||
height = intToFrac(width) / displayAspect;
|
||||
else if (windowAspect > displayAspect)
|
||||
width = fracToInt(height * displayAspect);
|
||||
}
|
||||
}
|
||||
|
||||
int16 alignX, alignY;
|
||||
switch (_screenAlign & SCREEN_ALIGN_XMASK) {
|
||||
default:
|
||||
case SCREEN_ALIGN_CENTER:
|
||||
alignX = ((rotatedWindowWidth - width) / 2);
|
||||
break;
|
||||
case SCREEN_ALIGN_LEFT:
|
||||
alignX = 0;
|
||||
break;
|
||||
case SCREEN_ALIGN_RIGHT:
|
||||
alignX = (rotatedSafeArea.right - width);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_screenAlign & SCREEN_ALIGN_YMASK) {
|
||||
default:
|
||||
case SCREEN_ALIGN_MIDDLE:
|
||||
alignY = ((rotatedWindowHeight - height) / 2);
|
||||
break;
|
||||
case SCREEN_ALIGN_TOP:
|
||||
alignY = 0;
|
||||
break;
|
||||
case SCREEN_ALIGN_BOTTOM:
|
||||
alignY = (rotatedSafeArea.bottom - height);
|
||||
break;
|
||||
}
|
||||
|
||||
rotatedSafeArea.constrain(alignX, alignY, width, height);
|
||||
|
||||
alignX += _gameScreenShakeXOffset * width / getWidth();
|
||||
alignY += _gameScreenShakeYOffset * height / getHeight();
|
||||
|
||||
if (_rotationMode == Common::kRotation90 || _rotationMode == Common::kRotation270) {
|
||||
drawRect.top = alignX;
|
||||
drawRect.left = alignY;
|
||||
drawRect.setWidth(height);
|
||||
drawRect.setHeight(width);
|
||||
} else {
|
||||
drawRect.left = alignX;
|
||||
drawRect.top = alignY;
|
||||
drawRect.setWidth(width);
|
||||
drawRect.setHeight(height);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user