Initial commit
This commit is contained in:
326
engines/ags/plugins/ags_flashlight/ags_flashlight.cpp
Normal file
326
engines/ags/plugins/ags_flashlight/ags_flashlight.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/* 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
|
||||
* of the License, or(at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/lib/allegro.h"
|
||||
#include "ags/plugins/ags_flashlight/ags_flashlight.h"
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace Plugins {
|
||||
namespace AGSFlashlight {
|
||||
|
||||
const uint32 Magic = 0xBABE0000;
|
||||
const uint32 Version = 2;
|
||||
const uint32 SaveMagic = Magic + Version;
|
||||
|
||||
const char *AGSFlashlight::AGS_GetPluginName() {
|
||||
return "Flashlight plugin recreation";
|
||||
}
|
||||
|
||||
void AGSFlashlight::AGS_EngineStartup(IAGSEngine *engine) {
|
||||
PluginBase::AGS_EngineStartup(engine);
|
||||
|
||||
if (_engine->version < 13)
|
||||
_engine->AbortGame("Engine interface is too old, need newer version of AGS.");
|
||||
|
||||
SCRIPT_METHOD(SetFlashlightTint, AGSFlashlight::SetFlashlightTint);
|
||||
SCRIPT_METHOD(GetFlashlightTintRed, AGSFlashlight::GetFlashlightTintRed);
|
||||
SCRIPT_METHOD(GetFlashlightTintGreen, AGSFlashlight::GetFlashlightTintGreen);
|
||||
SCRIPT_METHOD(GetFlashlightTintBlue, AGSFlashlight::GetFlashlightTintBlue);
|
||||
|
||||
SCRIPT_METHOD(GetFlashlightMinLightLevel, AGSFlashlight::GetFlashlightMinLightLevel);
|
||||
SCRIPT_METHOD(GetFlashlightMaxLightLevel, AGSFlashlight::GetFlashlightMaxLightLevel);
|
||||
|
||||
SCRIPT_METHOD(SetFlashlightDarkness, AGSFlashlight::SetFlashlightDarkness);
|
||||
SCRIPT_METHOD(GetFlashlightDarkness, AGSFlashlight::GetFlashlightDarkness);
|
||||
SCRIPT_METHOD(SetFlashlightDarknessSize, AGSFlashlight::SetFlashlightDarknessSize);
|
||||
SCRIPT_METHOD(GetFlashlightDarknessSize, AGSFlashlight::GetFlashlightDarknessSize);
|
||||
|
||||
SCRIPT_METHOD(SetFlashlightBrightness, AGSFlashlight::SetFlashlightBrightness);
|
||||
SCRIPT_METHOD(GetFlashlightBrightness, AGSFlashlight::GetFlashlightBrightness);
|
||||
SCRIPT_METHOD(SetFlashlightBrightnessSize, AGSFlashlight::SetFlashlightBrightnessSize);
|
||||
SCRIPT_METHOD(GetFlashlightBrightnessSize, AGSFlashlight::GetFlashlightBrightnessSize);
|
||||
|
||||
SCRIPT_METHOD(SetFlashlightPosition, AGSFlashlight::SetFlashlightPosition);
|
||||
SCRIPT_METHOD(GetFlashlightPositionX, AGSFlashlight::GetFlashlightPositionX);
|
||||
SCRIPT_METHOD(GetFlashlightPositionY, AGSFlashlight::GetFlashlightPositionY);
|
||||
|
||||
|
||||
SCRIPT_METHOD(SetFlashlightFollowMouse, AGSFlashlight::SetFlashlightFollowMouse);
|
||||
SCRIPT_METHOD(GetFlashlightFollowMouse, AGSFlashlight::GetFlashlightFollowMouse);
|
||||
|
||||
SCRIPT_METHOD(SetFlashlightFollowCharacter, AGSFlashlight::SetFlashlightFollowCharacter);
|
||||
SCRIPT_METHOD(GetFlashlightFollowCharacter, AGSFlashlight::GetFlashlightFollowCharacter);
|
||||
SCRIPT_METHOD(GetFlashlightCharacterDX, AGSFlashlight::GetFlashlightCharacterDX);
|
||||
SCRIPT_METHOD(GetFlashlightCharacterDY, AGSFlashlight::GetFlashlightCharacterDY);
|
||||
SCRIPT_METHOD(GetFlashlightCharacterHorz, AGSFlashlight::GetFlashlightCharacterHorz);
|
||||
SCRIPT_METHOD(GetFlashlightCharacterVert, AGSFlashlight::GetFlashlightCharacterVert);
|
||||
|
||||
SCRIPT_METHOD(SetFlashlightMask, AGSFlashlight::SetFlashlightMask);
|
||||
SCRIPT_METHOD(GetFlashlightMask, AGSFlashlight::GetFlashlightMask);
|
||||
|
||||
_engine->RequestEventHook(AGSE_PREGUIDRAW);
|
||||
_engine->RequestEventHook(AGSE_PRESCREENDRAW);
|
||||
_engine->RequestEventHook(AGSE_SAVEGAME);
|
||||
_engine->RequestEventHook(AGSE_RESTOREGAME);
|
||||
}
|
||||
|
||||
int64 AGSFlashlight::AGS_EngineOnEvent(int event, NumberPtr data) {
|
||||
if (event == AGSE_PREGUIDRAW) {
|
||||
Update();
|
||||
} else if (event == AGSE_RESTOREGAME) {
|
||||
Serializer s(_engine, data, true);
|
||||
syncGame(s);
|
||||
} else if (event == AGSE_SAVEGAME) {
|
||||
Serializer s(_engine, data, false);
|
||||
syncGame(s);
|
||||
} else if (event == AGSE_PRESCREENDRAW) {
|
||||
// Get screen size once here.
|
||||
_engine->GetScreenDimensions(&screen_width, &screen_height, &screen_color_depth);
|
||||
|
||||
// TODO: There's no reliable way to figure out if a game is running in legacy upscale mode from the
|
||||
// plugin interface, so for now let's just play it conservatively and check it per-game
|
||||
AGSGameInfo *gameInfo = new AGSGameInfo;
|
||||
gameInfo->Version = 26;
|
||||
_engine->GetGameInfo(gameInfo);
|
||||
if (gameInfo->UniqueId == 1050154255 || // MMD, MMM04, MMM13, MMM28, MMM46, MMM56, MMM57, MMM68, MMM78, MMMD9, MMMH5
|
||||
gameInfo->UniqueId == 1161197869) // MMM70
|
||||
g_ScaleFactor = (screen_width > 320) ? 2 : 1;
|
||||
|
||||
delete gameInfo;
|
||||
_engine->UnrequestEventHook(AGSE_PRESCREENDRAW);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AGSFlashlight::syncGame(Serializer &s) {
|
||||
uint32 SaveVersion = SaveMagic;
|
||||
s.syncAsInt(SaveVersion);
|
||||
|
||||
if (s.isLoading() && SaveVersion != SaveMagic) {
|
||||
// The real AGSFlashlight, or at least the one included with
|
||||
// Maniac Mansion Deluxe, doesn't persist any fields.
|
||||
// So in such a case, revert the 4 bytes and skip everything else
|
||||
s.unreadInt();
|
||||
|
||||
} else {
|
||||
s.syncAsInt(g_RedTint);
|
||||
s.syncAsInt(g_GreenTint);
|
||||
s.syncAsInt(g_BlueTint);
|
||||
|
||||
s.syncAsInt(g_DarknessLightLevel);
|
||||
s.syncAsInt(g_BrightnessLightLevel);
|
||||
s.syncAsInt(g_DarknessSize);
|
||||
s.syncAsInt(g_DarknessDiameter);
|
||||
s.syncAsInt(g_BrightnessSize);
|
||||
|
||||
s.syncAsInt(g_FlashlightX);
|
||||
s.syncAsInt(g_FlashlightY);
|
||||
|
||||
s.syncAsInt(g_FlashlightFollowMouse);
|
||||
|
||||
s.syncAsInt(g_FollowCharacterId);
|
||||
s.syncAsInt(g_FollowCharacterDx);
|
||||
s.syncAsInt(g_FollowCharacterDy);
|
||||
s.syncAsInt(g_FollowCharacterHorz);
|
||||
s.syncAsInt(g_FollowCharacterVert);
|
||||
|
||||
if (s.isLoading()) {
|
||||
if (g_FollowCharacterId != 0)
|
||||
g_FollowCharacter = _engine->GetCharacter(g_FollowCharacterId);
|
||||
|
||||
g_BitmapMustBeUpdated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AGSFlashlight::SetFlashlightTint(ScriptMethodParams ¶ms) {
|
||||
PARAMS3(int, RedTint, int, GreenTint, int, BlueTint);
|
||||
ClipToRange(RedTint, -31, 31);
|
||||
ClipToRange(GreenTint, -31, 31);
|
||||
ClipToRange(BlueTint, -31, 31);
|
||||
|
||||
if ((RedTint != g_RedTint) || (GreenTint != g_GreenTint) || (BlueTint != g_BlueTint))
|
||||
g_BitmapMustBeUpdated = true;
|
||||
|
||||
g_RedTint = RedTint;
|
||||
g_GreenTint = GreenTint;
|
||||
g_BlueTint = BlueTint;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightTintRed(ScriptMethodParams ¶ms) {
|
||||
params._result = g_RedTint;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightTintGreen(ScriptMethodParams ¶ms) {
|
||||
params._result = g_GreenTint;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightTintBlue(ScriptMethodParams ¶ms) {
|
||||
params._result = g_BlueTint;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightMinLightLevel(ScriptMethodParams ¶ms) {
|
||||
params._result = 0;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightMaxLightLevel(ScriptMethodParams ¶ms) {
|
||||
params._result = 100;
|
||||
}
|
||||
|
||||
void AGSFlashlight::SetFlashlightDarkness(ScriptMethodParams ¶ms) {
|
||||
PARAMS1(int, LightLevel);
|
||||
ClipToRange(LightLevel, 0, 100);
|
||||
|
||||
if (LightLevel != g_DarknessLightLevel) {
|
||||
g_BitmapMustBeUpdated = true;
|
||||
g_DarknessLightLevel = LightLevel;
|
||||
|
||||
if (g_DarknessLightLevel > g_BrightnessLightLevel)
|
||||
g_BrightnessLightLevel = g_DarknessLightLevel;
|
||||
}
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightDarkness(ScriptMethodParams ¶ms) {
|
||||
params._result = g_DarknessLightLevel;
|
||||
}
|
||||
|
||||
void AGSFlashlight::SetFlashlightDarknessSize(ScriptMethodParams ¶ms) {
|
||||
PARAMS1(int, Size);
|
||||
if (Size * g_ScaleFactor != g_DarknessSize) {
|
||||
g_BitmapMustBeUpdated = true;
|
||||
g_DarknessSize = Size * g_ScaleFactor;
|
||||
g_DarknessDiameter = g_DarknessSize * 2;
|
||||
|
||||
if (g_BrightnessSize > g_DarknessSize) {
|
||||
ScriptMethodParams p(g_DarknessSize / g_ScaleFactor);
|
||||
SetFlashlightBrightnessSize(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightDarknessSize(ScriptMethodParams ¶ms) {
|
||||
params._result = (g_DarknessSize / g_ScaleFactor);
|
||||
}
|
||||
|
||||
|
||||
void AGSFlashlight::SetFlashlightBrightness(ScriptMethodParams ¶ms) {
|
||||
PARAMS1(int, LightLevel);
|
||||
ClipToRange(LightLevel, 0, 100);
|
||||
|
||||
if (LightLevel != g_BrightnessLightLevel) {
|
||||
g_BitmapMustBeUpdated = true;
|
||||
g_BrightnessLightLevel = LightLevel;
|
||||
|
||||
if (g_BrightnessLightLevel < g_DarknessLightLevel)
|
||||
g_DarknessLightLevel = g_BrightnessLightLevel;
|
||||
}
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightBrightness(ScriptMethodParams ¶ms) {
|
||||
params._result = g_BrightnessLightLevel;
|
||||
}
|
||||
|
||||
void AGSFlashlight::SetFlashlightBrightnessSize(ScriptMethodParams ¶ms) {
|
||||
PARAMS1(int, Size);
|
||||
if (Size * g_ScaleFactor != g_BrightnessSize) {
|
||||
g_BitmapMustBeUpdated = true;
|
||||
g_BrightnessSize = Size * g_ScaleFactor;
|
||||
|
||||
if (g_DarknessSize < g_BrightnessSize) {
|
||||
ScriptMethodParams p(g_BrightnessSize / g_ScaleFactor);
|
||||
SetFlashlightDarknessSize(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightBrightnessSize(ScriptMethodParams ¶ms) {
|
||||
params._result = g_BrightnessSize / g_ScaleFactor;
|
||||
}
|
||||
|
||||
void AGSFlashlight::SetFlashlightPosition(ScriptMethodParams ¶ms) {
|
||||
PARAMS2(int, X, int, Y);
|
||||
g_FlashlightX = X;
|
||||
g_FlashlightY = Y;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightPositionX(ScriptMethodParams ¶ms) {
|
||||
params._result = g_FlashlightX;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightPositionY(ScriptMethodParams ¶ms) {
|
||||
params._result = g_FlashlightY;
|
||||
}
|
||||
|
||||
void AGSFlashlight::SetFlashlightFollowMouse(ScriptMethodParams ¶ms) {
|
||||
PARAMS1(int, OnOff);
|
||||
g_FlashlightFollowMouse = (OnOff != 0);
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightFollowMouse(ScriptMethodParams ¶ms) {
|
||||
params._result = g_FlashlightFollowMouse ? 1 : 0;
|
||||
}
|
||||
|
||||
void AGSFlashlight::SetFlashlightFollowCharacter(ScriptMethodParams ¶ms) {
|
||||
PARAMS5(int, CharacterId, int, dx, int, dy, int, horz, int, vert);
|
||||
g_FollowCharacterId = CharacterId;
|
||||
g_FollowCharacterDx = dx;
|
||||
g_FollowCharacterDy = dy;
|
||||
g_FollowCharacterHorz = horz;
|
||||
g_FollowCharacterVert = vert;
|
||||
|
||||
g_FollowCharacter = _engine->GetCharacter(CharacterId);
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightFollowCharacter(ScriptMethodParams ¶ms) {
|
||||
params._result = g_FollowCharacterId;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightCharacterDX(ScriptMethodParams ¶ms) {
|
||||
params._result = g_FollowCharacterDx;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightCharacterDY(ScriptMethodParams ¶ms) {
|
||||
params._result = g_FollowCharacterDy;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightCharacterHorz(ScriptMethodParams ¶ms) {
|
||||
params._result = g_FollowCharacterHorz;
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightCharacterVert(ScriptMethodParams ¶ms) {
|
||||
params._result = g_FollowCharacterVert;
|
||||
}
|
||||
|
||||
void AGSFlashlight::SetFlashlightMask(ScriptMethodParams ¶ms) {
|
||||
//PARAMS1(int, SpriteSlot);
|
||||
// Not implemented.
|
||||
}
|
||||
|
||||
void AGSFlashlight::GetFlashlightMask(ScriptMethodParams ¶ms) {
|
||||
params._result = 0;
|
||||
}
|
||||
|
||||
} // namespace AGSFlashlight
|
||||
} // namespace Plugins
|
||||
} // namespace AGS3
|
||||
127
engines/ags/plugins/ags_flashlight/ags_flashlight.h
Normal file
127
engines/ags/plugins/ags_flashlight/ags_flashlight.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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
|
||||
* of the License, or(at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_PLUGINS_AGSFLASHLIGHT_AGSFLASHLIGHT_H
|
||||
#define AGS_PLUGINS_AGSFLASHLIGHT_AGSFLASHLIGHT_H
|
||||
|
||||
#include "ags/plugins/ags_plugin.h"
|
||||
#include "ags/plugins/serializer.h"
|
||||
#include "ags/lib/allegro.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace Plugins {
|
||||
namespace AGSFlashlight {
|
||||
|
||||
/**
|
||||
* This is not the AGS Flashlight plugin,
|
||||
* but a workalike plugin originally created for the AGS engine PSP port.
|
||||
*/
|
||||
class AGSFlashlight : public PluginBase {
|
||||
SCRIPT_HASH(AGSFlashlight)
|
||||
private:
|
||||
int32 screen_width = 320;
|
||||
int32 screen_height = 200;
|
||||
int32 screen_color_depth = 16;
|
||||
bool g_BitmapMustBeUpdated = true;
|
||||
int g_RedTint = 0;
|
||||
int g_GreenTint = 0;
|
||||
int g_BlueTint = 0;
|
||||
int g_DarknessLightLevel = 100;
|
||||
int g_BrightnessLightLevel = 100;
|
||||
int g_DarknessSize = 0;
|
||||
int g_DarknessDiameter = 0;
|
||||
int g_BrightnessSize = 0;
|
||||
int g_ScaleFactor = 1;
|
||||
int32 g_FlashlightX = 0;
|
||||
int32 g_FlashlightY = 0;
|
||||
int32 g_FlashlightDrawAtX = 0;
|
||||
int32 g_FlashlightDrawAtY = 0;
|
||||
bool g_FlashlightFollowMouse = false;
|
||||
int g_FollowCharacterId = 0;
|
||||
int g_FollowCharacterDx = 0;
|
||||
int g_FollowCharacterDy = 0;
|
||||
int g_FollowCharacterHorz = 0;
|
||||
int g_FollowCharacterVert = 0;
|
||||
AGSCharacter *g_FollowCharacter = nullptr;
|
||||
BITMAP *g_LightBitmap = nullptr;
|
||||
uint32 flashlight_x = 0, flashlight_n = 0;
|
||||
|
||||
private:
|
||||
/**
|
||||
* This function is from Allegro, split for more performance.
|
||||
* Combines a 32 bit RGBA sprite with a 16 bit RGB destination, optimised
|
||||
* for when one pixel is in an RGB layout and the other is BGR.
|
||||
*/
|
||||
inline uint32 _blender_alpha16_bgr(uint32 y);
|
||||
inline void calc_x_n(uint32 x);
|
||||
inline void setPixel(int x, int y, uint32 color, uint32 *pixel);
|
||||
void plotCircle(int xm, int ym, int r, uint32 color);
|
||||
void ClipToRange(int &variable, int min, int max);
|
||||
void AlphaBlendBitmap();
|
||||
void DrawTint();
|
||||
void DrawDarkness();
|
||||
void CreateLightBitmap();
|
||||
void Update();
|
||||
uint32 blendPixel(uint32 col, bool isAlpha24, int light);
|
||||
void syncGame(Serializer &s);
|
||||
|
||||
void SetFlashlightTint(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightTintRed(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightTintGreen(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightTintBlue(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightMinLightLevel(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightMaxLightLevel(ScriptMethodParams ¶ms);
|
||||
void SetFlashlightDarkness(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightDarkness(ScriptMethodParams ¶ms);
|
||||
void SetFlashlightDarknessSize(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightDarknessSize(ScriptMethodParams ¶ms);
|
||||
void SetFlashlightBrightness(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightBrightness(ScriptMethodParams ¶ms);
|
||||
void SetFlashlightBrightnessSize(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightBrightnessSize(ScriptMethodParams ¶ms);
|
||||
void SetFlashlightPosition(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightPositionX(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightPositionY(ScriptMethodParams ¶ms);
|
||||
void SetFlashlightFollowMouse(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightFollowMouse(ScriptMethodParams ¶ms);
|
||||
void SetFlashlightFollowCharacter(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightFollowCharacter(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightCharacterDX(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightCharacterDY(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightCharacterHorz(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightCharacterVert(ScriptMethodParams ¶ms);
|
||||
void SetFlashlightMask(ScriptMethodParams ¶ms);
|
||||
void GetFlashlightMask(ScriptMethodParams ¶ms);
|
||||
public:
|
||||
AGSFlashlight() : PluginBase() {}
|
||||
virtual ~AGSFlashlight() {}
|
||||
|
||||
const char *AGS_GetPluginName() override;
|
||||
void AGS_EngineStartup(IAGSEngine *engine) override;
|
||||
int64 AGS_EngineOnEvent(int event, NumberPtr data) override;
|
||||
int AGS_PluginV2() const override { return 1; };
|
||||
};
|
||||
|
||||
} // namespace AGSFlashlight
|
||||
} // namespace Plugins
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
373
engines/ags/plugins/ags_flashlight/gfx.cpp
Normal file
373
engines/ags/plugins/ags_flashlight/gfx.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
/* 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
|
||||
* of the License, or(at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/plugins/ags_flashlight/ags_flashlight.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace Plugins {
|
||||
namespace AGSFlashlight {
|
||||
|
||||
void AGSFlashlight::calc_x_n(uint32 _x) {
|
||||
flashlight_x = _x;
|
||||
|
||||
flashlight_n = flashlight_x >> 24;
|
||||
|
||||
if (flashlight_n)
|
||||
flashlight_n = (flashlight_n + 1) / 8;
|
||||
|
||||
flashlight_x = ((flashlight_x >> 19) & 0x001F) | ((flashlight_x >> 5) & 0x07E0) | ((flashlight_x << 8) & 0xF800);
|
||||
|
||||
flashlight_x = (flashlight_x | (flashlight_x << 16)) & 0x7E0F81F;
|
||||
}
|
||||
|
||||
|
||||
uint32 AGSFlashlight::_blender_alpha16_bgr(uint32 y) {
|
||||
uint32 result;
|
||||
|
||||
y = ((y & 0xFFFF) | (y << 16)) & 0x7E0F81F;
|
||||
|
||||
result = ((flashlight_x - y) * flashlight_n / 32 + y) & 0x7E0F81F;
|
||||
|
||||
return ((result & 0xFFFF) | (result >> 16));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AGSFlashlight::setPixel(int x, int y, uint32 color, uint32 *pixel) {
|
||||
if ((x >= g_DarknessDiameter) || (y >= g_DarknessDiameter) || (x < 0) || (y < 0))
|
||||
return;
|
||||
|
||||
*(pixel + (y * g_DarknessDiameter) + x) = color;
|
||||
}
|
||||
|
||||
|
||||
void AGSFlashlight::plotCircle(int xm, int ym, int r, uint32 color) {
|
||||
uint32 *pixel = (uint32 *)_engine->GetRawBitmapSurface(g_LightBitmap);
|
||||
|
||||
int x = -r;
|
||||
int y = 0;
|
||||
int err = 2 - 2 * r;
|
||||
|
||||
do {
|
||||
setPixel(xm - x, ym + y, color, pixel); // I. Quadrant
|
||||
setPixel(xm - x - 1, ym + y, color, pixel);
|
||||
|
||||
setPixel(xm - y, ym - x, color, pixel); // II. Quadrant
|
||||
setPixel(xm - y, ym - x - 1, color, pixel);
|
||||
|
||||
setPixel(xm + x, ym - y, color, pixel); // III. Quadrant
|
||||
setPixel(xm + x + 1, ym - y, color, pixel);
|
||||
|
||||
setPixel(xm + y, ym + x, color, pixel); // IV. Quadrant
|
||||
setPixel(xm + y, ym + x + 1, color, pixel);
|
||||
|
||||
r = err;
|
||||
if (r > x)
|
||||
err += ++x * 2 + 1;
|
||||
|
||||
if (r <= y)
|
||||
err += ++y * 2 + 1;
|
||||
} while (x < 0);
|
||||
|
||||
_engine->ReleaseBitmapSurface(g_LightBitmap);
|
||||
}
|
||||
|
||||
|
||||
void AGSFlashlight::ClipToRange(int &variable, int min, int max) {
|
||||
if (variable < min)
|
||||
variable = min;
|
||||
|
||||
if (variable > max)
|
||||
variable = max;
|
||||
}
|
||||
|
||||
|
||||
void AGSFlashlight::AlphaBlendBitmap() {
|
||||
uint16 *destpixel = (uint16 *)_engine->GetRawBitmapSurface(_engine->GetVirtualScreen());
|
||||
uint32 *sourcepixel = (uint32 *)_engine->GetRawBitmapSurface(g_LightBitmap);
|
||||
|
||||
uint16 *currentdestpixel = destpixel;
|
||||
uint32 *currentsourcepixel = sourcepixel;
|
||||
|
||||
int x, y;
|
||||
|
||||
int targetX = (g_FlashlightDrawAtX > -1) ? g_FlashlightDrawAtX : 0;
|
||||
int targetY = (g_FlashlightDrawAtY > -1) ? g_FlashlightDrawAtY : 0;
|
||||
|
||||
int startX = (g_FlashlightDrawAtX < 0) ? -1 * g_FlashlightDrawAtX : 0;
|
||||
int endX = (g_FlashlightDrawAtX + g_DarknessDiameter < screen_width) ? g_DarknessDiameter : g_DarknessDiameter - ((g_FlashlightDrawAtX + g_DarknessDiameter) - screen_width);
|
||||
|
||||
int startY = (g_FlashlightDrawAtY < 0) ? -1 * g_FlashlightDrawAtY : 0;
|
||||
int endY = (g_FlashlightDrawAtY + g_DarknessDiameter < screen_height) ? g_DarknessDiameter : g_DarknessDiameter - ((g_FlashlightDrawAtY + g_DarknessDiameter) - screen_height);
|
||||
|
||||
for (y = 0; y < endY - startY; y++) {
|
||||
currentdestpixel = destpixel + (y + targetY) * screen_width + targetX;
|
||||
currentsourcepixel = sourcepixel + (y + startY) * g_DarknessDiameter + startX;
|
||||
|
||||
for (x = 0; x < endX - startX; x++) {
|
||||
calc_x_n(*currentsourcepixel);
|
||||
*currentdestpixel = (uint16)_blender_alpha16_bgr(*currentdestpixel);
|
||||
|
||||
currentdestpixel++;
|
||||
currentsourcepixel++;
|
||||
}
|
||||
}
|
||||
|
||||
_engine->ReleaseBitmapSurface(_engine->GetVirtualScreen());
|
||||
_engine->ReleaseBitmapSurface(g_LightBitmap);
|
||||
}
|
||||
|
||||
|
||||
void AGSFlashlight::DrawTint() {
|
||||
int x, y;
|
||||
BITMAP *screen = _engine->GetVirtualScreen();
|
||||
uint16 *destpixel = (uint16 *)_engine->GetRawBitmapSurface(screen);
|
||||
|
||||
int32 red, blue, green, alpha;
|
||||
|
||||
for (y = 0; y < screen_height; y++) {
|
||||
for (x = 0; x < screen_width; x++) {
|
||||
_engine->GetRawColorComponents(16, *destpixel, &red, &green, &blue, &alpha);
|
||||
|
||||
if (g_RedTint != 0) {
|
||||
red += g_RedTint * 8;
|
||||
if (red > 255)
|
||||
red = 255;
|
||||
else if (red < 0)
|
||||
red = 0;
|
||||
}
|
||||
|
||||
if (g_BlueTint != 0) {
|
||||
blue += g_BlueTint * 8;
|
||||
if (blue > 255)
|
||||
blue = 255;
|
||||
else if (blue < 0)
|
||||
blue = 0;
|
||||
}
|
||||
|
||||
if (g_GreenTint != 0) {
|
||||
green += g_GreenTint * 8;
|
||||
if (green > 255)
|
||||
green = 255;
|
||||
else if (green < 0)
|
||||
green = 0;
|
||||
}
|
||||
|
||||
*destpixel = _engine->MakeRawColorPixel(16, red, green, blue, alpha);
|
||||
destpixel++;
|
||||
}
|
||||
}
|
||||
|
||||
_engine->ReleaseBitmapSurface(screen);
|
||||
}
|
||||
|
||||
|
||||
void AGSFlashlight::DrawDarkness() {
|
||||
int x, y;
|
||||
uint32 color = (255 - (int)((float)g_DarknessLightLevel * 2.55f)) << 24;
|
||||
BITMAP *screen = _engine->GetVirtualScreen();
|
||||
assert(screen->format.bytesPerPixel == 2);
|
||||
uint16 *destpixel = (uint16 *)_engine->GetRawBitmapSurface(screen);
|
||||
uint16 *currentpixel;
|
||||
|
||||
calc_x_n(color);
|
||||
|
||||
if (g_DarknessSize == 0) {
|
||||
// Whole screen.
|
||||
for (x = 0; x < screen_width * screen_height; x++) {
|
||||
*destpixel = (uint16)_blender_alpha16_bgr(*destpixel);
|
||||
destpixel++;
|
||||
}
|
||||
} else {
|
||||
// Top.
|
||||
if (g_FlashlightDrawAtY > -1) {
|
||||
currentpixel = destpixel;
|
||||
for (y = 0; y < g_FlashlightDrawAtY; y++) {
|
||||
for (x = 0; x < screen_width; x++) {
|
||||
*currentpixel = (uint16)_blender_alpha16_bgr(*currentpixel);
|
||||
currentpixel++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom.
|
||||
if (g_FlashlightDrawAtY + g_DarknessDiameter < screen_height) {
|
||||
currentpixel = destpixel + (g_FlashlightDrawAtY + g_DarknessDiameter) * screen_width;
|
||||
for (y = g_FlashlightDrawAtY + g_DarknessDiameter; y < screen_height; y++) {
|
||||
for (x = 0; x < screen_width; x++) {
|
||||
*currentpixel = (uint16)_blender_alpha16_bgr(*currentpixel);
|
||||
currentpixel++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Left.
|
||||
if (g_FlashlightDrawAtX > 0) {
|
||||
currentpixel = destpixel;
|
||||
int startpoint = (g_FlashlightDrawAtY > 0) ? g_FlashlightDrawAtY : 0;
|
||||
int endpoint = (g_FlashlightDrawAtY + g_DarknessDiameter >= screen_height) ? screen_height + 1 : g_FlashlightDrawAtY + g_DarknessDiameter + 1;
|
||||
for (y = startpoint; y < endpoint; y++) {
|
||||
for (x = 0; x < g_FlashlightDrawAtX; x++) {
|
||||
*currentpixel = (uint16)_blender_alpha16_bgr(*currentpixel);
|
||||
currentpixel++;
|
||||
}
|
||||
|
||||
currentpixel = destpixel + screen_width * y;
|
||||
}
|
||||
}
|
||||
|
||||
// Right.
|
||||
if (g_FlashlightDrawAtX + g_DarknessDiameter < screen_width) {
|
||||
currentpixel = destpixel + (g_FlashlightDrawAtX + g_DarknessDiameter);
|
||||
int startpoint = (g_FlashlightDrawAtY > 0) ? g_FlashlightDrawAtY : 0;
|
||||
int endpoint = (g_FlashlightDrawAtY + g_DarknessDiameter >= screen_height) ? screen_height + 1 : g_FlashlightDrawAtY + g_DarknessDiameter + 1;
|
||||
for (y = startpoint; y < endpoint; y++) {
|
||||
for (x = g_FlashlightDrawAtX + g_DarknessDiameter; x < screen_width; x++) {
|
||||
*currentpixel = (uint16)_blender_alpha16_bgr(*currentpixel);
|
||||
currentpixel++;
|
||||
}
|
||||
|
||||
currentpixel = destpixel + screen_width * y + (g_FlashlightDrawAtX + g_DarknessDiameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_engine->ReleaseBitmapSurface(screen);
|
||||
}
|
||||
|
||||
|
||||
void AGSFlashlight::CreateLightBitmap() {
|
||||
if (g_DarknessSize == 0)
|
||||
return;
|
||||
|
||||
if (g_LightBitmap)
|
||||
_engine->FreeBitmap(g_LightBitmap);
|
||||
|
||||
g_LightBitmap = _engine->CreateBlankBitmap(g_DarknessDiameter, g_DarknessDiameter, 32);
|
||||
|
||||
// Fill with darkness color.
|
||||
uint32 color = (255 - (int)((float)g_DarknessLightLevel * 2.55f)) << 24;
|
||||
uint32 *pixel = (uint32 *)_engine->GetRawBitmapSurface(g_LightBitmap);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < g_DarknessDiameter * g_DarknessDiameter; i++)
|
||||
*pixel++ = (uint32)color;
|
||||
|
||||
// Draw light circle if wanted.
|
||||
if (g_DarknessSize > 0 && g_DarknessLightLevel != g_BrightnessLightLevel) {
|
||||
uint32 current_value = 0;
|
||||
color = (255 - (int)((float)g_BrightnessLightLevel * 2.55f));
|
||||
uint32 targetcolor = ((255 - (int)((float)g_DarknessLightLevel * 2.55f)));
|
||||
|
||||
int increment = (targetcolor - color) / (g_DarknessSize - g_BrightnessSize);
|
||||
float perfect_increment = (float)(targetcolor - color) / (float)(g_DarknessSize - g_BrightnessSize);
|
||||
|
||||
float error_term;
|
||||
|
||||
for (i = g_BrightnessSize; i < g_DarknessSize; i++) {
|
||||
error_term = (perfect_increment * (i - g_BrightnessSize)) - current_value;
|
||||
|
||||
if (error_term >= 1.0f)
|
||||
increment++;
|
||||
else if (error_term <= -1.0f)
|
||||
increment--;
|
||||
|
||||
current_value += increment;
|
||||
|
||||
if (current_value > targetcolor)
|
||||
current_value = targetcolor;
|
||||
|
||||
plotCircle(g_DarknessSize, g_DarknessSize, i, (current_value << 24) + color);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw inner fully lit circle.
|
||||
if (g_BrightnessSize > 0) {
|
||||
color = (255 - (int)((float)g_BrightnessLightLevel * 2.55f)) << 24;
|
||||
|
||||
for (i = 0; i < g_BrightnessSize; i++)
|
||||
plotCircle(g_DarknessSize, g_DarknessSize, i, color);
|
||||
}
|
||||
|
||||
_engine->ReleaseBitmapSurface(g_LightBitmap);
|
||||
}
|
||||
|
||||
|
||||
void AGSFlashlight::Update() {
|
||||
if (g_BitmapMustBeUpdated) {
|
||||
CreateLightBitmap();
|
||||
g_BitmapMustBeUpdated = false;
|
||||
}
|
||||
|
||||
if (g_FlashlightFollowMouse) {
|
||||
_engine->GetMousePosition(&g_FlashlightX, &g_FlashlightY);
|
||||
} else if (g_FollowCharacter != nullptr) {
|
||||
g_FlashlightX = g_FollowCharacter->x + g_FollowCharacterDx;
|
||||
g_FlashlightY = g_FollowCharacter->y + g_FollowCharacterDy;
|
||||
|
||||
if ((g_FollowCharacterHorz != 0) || (g_FollowCharacterVert != 0)) {
|
||||
switch (g_FollowCharacter->loop) {
|
||||
// Down
|
||||
case 0:
|
||||
case 4:
|
||||
case 6:
|
||||
g_FlashlightY += g_FollowCharacterVert;
|
||||
break;
|
||||
|
||||
// Up
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
g_FlashlightY -= g_FollowCharacterVert;
|
||||
break;
|
||||
|
||||
// Left
|
||||
case 1:
|
||||
g_FlashlightX -= g_FollowCharacterHorz;
|
||||
break;
|
||||
|
||||
// Right:
|
||||
case 2:
|
||||
g_FlashlightX += g_FollowCharacterHorz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_FlashlightDrawAtX = g_FlashlightX - g_DarknessSize;
|
||||
g_FlashlightDrawAtY = g_FlashlightY - g_DarknessSize;
|
||||
|
||||
|
||||
if ((g_GreenTint != 0) || (g_RedTint != 0) || (g_BlueTint != 0))
|
||||
DrawTint();
|
||||
|
||||
if (g_DarknessSize > 0)
|
||||
AlphaBlendBitmap();
|
||||
|
||||
if (g_DarknessLightLevel != 100)
|
||||
DrawDarkness();
|
||||
|
||||
_engine->MarkRegionDirty(0, 0, screen_width, screen_height);
|
||||
}
|
||||
|
||||
} // namespace AGSFlashlight
|
||||
} // namespace Plugins
|
||||
} // namespace AGS3
|
||||
Reference in New Issue
Block a user