1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-25 21:38:59 +02:00

Existing software cursor logic is now in a separate class

This commit is contained in:
Ivan Savenko 2023-01-05 21:30:54 +02:00
parent 0e8ee929df
commit 9971bdca1b
5 changed files with 155 additions and 111 deletions

View File

@ -12,60 +12,33 @@
#include <SDL.h>
#include "SDL_Extensions.h"
#include "CGuiHandler.h"
#include "../widgets/Images.h"
#include "CAnimation.h"
#include "../CMT.h"
void CursorHandler::clearBuffer()
{
Uint32 fillColor = SDL_MapRGBA(buffer->format, 0, 0, 0, 0);
CSDL_Ext::fillRect(buffer, nullptr, fillColor);
}
void CursorHandler::updateBuffer(CIntObject * payload)
{
payload->moveTo(Point(0,0));
payload->showAll(buffer);
needUpdate = true;
}
void CursorHandler::replaceBuffer(CIntObject * payload)
{
clearBuffer();
updateBuffer(payload);
}
CursorHandler::CursorHandler()
: needUpdate(true)
, buffer(nullptr)
, cursorLayer(nullptr)
: cursorSW(new CursorSoftware())
, frameTime(0.f)
, showing(false)
, pos(0,0)
{
cursorLayer = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 40, 40);
SDL_SetTextureBlendMode(cursorLayer, SDL_BLENDMODE_BLEND);
type = Cursor::Type::DEFAULT;
dndObject = nullptr;
cursors =
{
std::make_unique<CAnimImage>("CRADVNTR", 0),
std::make_unique<CAnimImage>("CRCOMBAT", 0),
std::make_unique<CAnimImage>("CRDEFLT", 0),
std::make_unique<CAnimImage>("CRSPELL", 0)
std::make_unique<CAnimation>("CRADVNTR"),
std::make_unique<CAnimation>("CRCOMBAT"),
std::make_unique<CAnimation>("CRDEFLT"),
std::make_unique<CAnimation>("CRSPELL")
};
currentCursor = cursors.at(static_cast<size_t>(Cursor::Type::DEFAULT)).get();
buffer = CSDL_Ext::newSurface(40,40);
SDL_SetSurfaceBlendMode(buffer, SDL_BLENDMODE_NONE);
SDL_ShowCursor(SDL_DISABLE);
for (auto & cursor : cursors)
cursor->preload();
set(Cursor::Map::POINTER);
}
@ -79,20 +52,10 @@ void CursorHandler::changeGraphic(Cursor::Type type, size_t index)
{
assert(dndObject == nullptr);
if(type != this->type)
{
this->type = type;
this->frame = index;
currentCursor = cursors.at(static_cast<size_t>(type)).get();
currentCursor->setFrame(index);
}
else if(index != this->frame)
{
this->frame = index;
currentCursor->setFrame(index);
}
this->type = type;
this->frame = index;
replaceBuffer(currentCursor);
cursorSW->setImage(getCurrentImage(), getPivotOffset());
}
void CursorHandler::set(Cursor::Default index)
@ -116,19 +79,25 @@ void CursorHandler::set(Cursor::Spellcast index)
changeGraphic(Cursor::Type::SPELLBOOK, frame);
}
void CursorHandler::dragAndDropCursor(std::unique_ptr<CAnimImage> object)
void CursorHandler::dragAndDropCursor(std::shared_ptr<IImage> image)
{
dndObject = std::move(object);
if(dndObject)
replaceBuffer(dndObject.get());
else
replaceBuffer(currentCursor);
dndObject = image;
cursorSW->setImage(getCurrentImage(), getPivotOffset());
}
void CursorHandler::dragAndDropCursor (std::string path, size_t index)
{
CAnimation anim(path);
anim.load(index);
dragAndDropCursor(anim.getImage(index));
}
void CursorHandler::cursorMove(const int & x, const int & y)
{
pos.x = x;
pos.y = y;
cursorSW->setCursorPosition(pos);
}
Point CursorHandler::getPivotOffsetDefault(size_t index)
@ -233,6 +202,9 @@ Point CursorHandler::getPivotOffsetSpellcast()
Point CursorHandler::getPivotOffset()
{
if (dndObject)
return dndObject->dimensions();
switch (type) {
case Cursor::Type::ADVENTURE: return getPivotOffsetMap(frame);
case Cursor::Type::COMBAT: return getPivotOffsetCombat(frame);
@ -244,13 +216,24 @@ Point CursorHandler::getPivotOffset()
return {0, 0};
}
std::shared_ptr<IImage> CursorHandler::getCurrentImage()
{
if (dndObject)
return dndObject;
return cursors[static_cast<size_t>(type)]->getImage(frame);
}
void CursorHandler::centerCursor()
{
pos.x = static_cast<int>((screen->w / 2.) - (currentCursor->pos.w / 2.));
pos.y = static_cast<int>((screen->h / 2.) - (currentCursor->pos.h / 2.));
Point screenSize {screen->w, screen->h};
pos = screenSize / 2 - getPivotOffset();
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
SDL_WarpMouse(pos.x, pos.y);
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
cursorSW->setCursorPosition(pos);
}
void CursorHandler::updateSpellcastCursor()
@ -260,7 +243,7 @@ void CursorHandler::updateSpellcastCursor()
frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f;
size_t newFrame = frame;
while (frameTime > frameDisplayDuration)
while (frameTime >= frameDisplayDuration)
{
frameTime -= frameDisplayDuration;
newFrame++;
@ -268,7 +251,7 @@ void CursorHandler::updateSpellcastCursor()
auto & animation = cursors.at(static_cast<size_t>(type));
while (newFrame > animation->size())
while (newFrame >= animation->size())
newFrame -= animation->size();
changeGraphic(Cursor::Type::SPELLBOOK, newFrame);
@ -282,16 +265,16 @@ void CursorHandler::render()
if (type == Cursor::Type::SPELLBOOK)
updateSpellcastCursor();
cursorSW->render();
}
//the must update texture in the main (renderer) thread, but changes to cursor type may come from other threads
updateTexture();
void CursorSoftware::render()
{
//texture must be updated in the main (renderer) thread, but changes to cursor type may come from other threads
if (needUpdate)
updateTexture();
Point renderPos = pos;
if(dndObject)
renderPos -= dndObject->pos.dimensions() / 2;
else
renderPos -= getPivotOffset();
Point renderPos = pos - pivot;
SDL_Rect destRect;
destRect.x = renderPos.x;
@ -299,23 +282,67 @@ void CursorHandler::render()
destRect.w = 40;
destRect.h = 40;
SDL_RenderCopy(mainRenderer, cursorLayer, nullptr, &destRect);
SDL_RenderCopy(mainRenderer, cursorTexture, nullptr, &destRect);
}
void CursorHandler::updateTexture()
void CursorSoftware::createTexture(const Point & dimensions)
{
if(needUpdate)
{
SDL_UpdateTexture(cursorLayer, nullptr, buffer->pixels, buffer->pitch);
needUpdate = false;
}
if(cursorTexture)
SDL_DestroyTexture(cursorTexture);
if (cursorSurface)
SDL_FreeSurface(cursorSurface);
cursorSurface = CSDL_Ext::newSurface(dimensions.x, dimensions.y);
cursorTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dimensions.x, dimensions.y);
SDL_SetSurfaceBlendMode(cursorSurface, SDL_BLENDMODE_NONE);
SDL_SetTextureBlendMode(cursorTexture, SDL_BLENDMODE_BLEND);
}
CursorHandler::~CursorHandler()
void CursorSoftware::updateTexture()
{
if(buffer)
SDL_FreeSurface(buffer);
Point dimensions(-1, -1);
if (!cursorSurface || Point(cursorSurface->w, cursorSurface->h) != cursorImage->dimensions())
createTexture(cursorImage->dimensions());
Uint32 fillColor = SDL_MapRGBA(cursorSurface->format, 0, 0, 0, 0);
CSDL_Ext::fillRect(cursorSurface, nullptr, fillColor);
cursorImage->draw(cursorSurface);
SDL_UpdateTexture(cursorTexture, NULL, cursorSurface->pixels, cursorSurface->pitch);
needUpdate = false;
}
void CursorSoftware::setImage(std::shared_ptr<IImage> image, const Point & pivotOffset)
{
assert(image != nullptr);
cursorImage = image;
pivot = pivotOffset;
needUpdate = true;
}
void CursorSoftware::setCursorPosition( const Point & newPos )
{
pos = newPos;
}
CursorSoftware::CursorSoftware():
cursorTexture(nullptr),
cursorSurface(nullptr),
needUpdate(false),
pivot(0,0)
{
SDL_ShowCursor(SDL_DISABLE);
}
CursorSoftware::~CursorSoftware()
{
if(cursorTexture)
SDL_DestroyTexture(cursorTexture);
if (cursorSurface)
SDL_FreeSurface(cursorSurface);
if(cursorLayer)
SDL_DestroyTexture(cursorLayer);
}

View File

@ -9,8 +9,8 @@
*/
#pragma once
class CIntObject;
class CAnimImage;
class CAnimation;
class IImage;
struct SDL_Surface;
struct SDL_Texture;
@ -111,37 +111,52 @@ namespace Cursor
};
}
class CursorHardware
{
//TODO
};
class CursorSoftware
{
std::shared_ptr<IImage> cursorImage;
SDL_Texture * cursorTexture;
SDL_Surface * cursorSurface;
Point pos;
Point pivot;
bool needUpdate;
void createTexture(const Point & dimensions);
void updateTexture();
public:
CursorSoftware();
~CursorSoftware();
void setImage(std::shared_ptr<IImage> image, const Point & pivotOffset);
void setCursorPosition( const Point & newPos );
void render();
void setVisible(bool on);
};
/// handles mouse cursor
class CursorHandler final
{
bool needUpdate;
SDL_Texture * cursorLayer;
std::shared_ptr<IImage> dndObject; //if set, overrides currentCursor
SDL_Surface * buffer;
CAnimImage * currentCursor;
std::unique_ptr<CAnimImage> dndObject; //if set, overrides currentCursor
std::array<std::unique_ptr<CAnimImage>, 4> cursors;
std::array<std::unique_ptr<CAnimation>, 4> cursors;
bool showing;
void clearBuffer();
void updateBuffer(CIntObject * payload);
void replaceBuffer(CIntObject * payload);
void updateTexture();
/// Current cursor
Cursor::Type type;
size_t frame;
float frameTime;
Point pos;
void changeGraphic(Cursor::Type type, size_t index);
/// position of cursor
Point pos;
Point getPivotOffsetDefault(size_t index);
Point getPivotOffsetMap(size_t index);
Point getPivotOffsetCombat(size_t index);
@ -149,17 +164,19 @@ class CursorHandler final
Point getPivotOffset();
void updateSpellcastCursor();
std::shared_ptr<IImage> getCurrentImage();
std::unique_ptr<CursorSoftware> cursorSW;
public:
CursorHandler();
~CursorHandler();
/**
* Replaces the cursor with a custom image.
*
* @param image Image to replace cursor with or nullptr to use the normal
* cursor. CursorHandler takes ownership of object
*/
void dragAndDropCursor (std::unique_ptr<CAnimImage> image);
/// Replaces the cursor with a custom image.
/// @param image Image to replace cursor with or nullptr to use the normal cursor.
void dragAndDropCursor(std::shared_ptr<IImage> image);
void dragAndDropCursor(std::string path, size_t index);
/// Returns current position of the cursor
Point position() const;

View File

@ -257,7 +257,7 @@ void CHeroArtPlace::clickRight(tribool down, bool previousState)
void CArtifactsOfHero::activate()
{
if (commonInfo->src.AOH == this && commonInfo->src.art)
CCS->curh->dragAndDropCursor(std::make_unique<CAnimImage>("artifact", commonInfo->src.art->artType->getIconIndex()));
CCS->curh->dragAndDropCursor("artifact", commonInfo->src.art->artType->getIconIndex());
CIntObject::activate();
}
@ -289,7 +289,7 @@ void CHeroArtPlace::select ()
}
}
CCS->curh->dragAndDropCursor(std::make_unique<CAnimImage>("artifact", ourArt->artType->getIconIndex()));
CCS->curh->dragAndDropCursor("artifact", ourArt->artType->getIconIndex());
ourOwner->commonInfo->src.setTo(this, false);
ourOwner->markPossibleSlots(ourArt);
@ -752,7 +752,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation & src, const Artifac
{
auto art = curHero->getArt(ArtifactPosition::TRANSITION_POS);
assert(art);
CCS->curh->dragAndDropCursor(std::make_unique<CAnimImage>("artifact", art->artType->getIconIndex()));
CCS->curh->dragAndDropCursor("artifact", art->artType->getIconIndex());
markPossibleSlots(art);
commonInfo->src.art = art;
@ -787,7 +787,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation & src, const Artifac
commonInfo->src.art = dst.getArt();
commonInfo->src.slotID = dst.slot;
assert(commonInfo->src.AOH);
CCS->curh->dragAndDropCursor(std::make_unique<CAnimImage>("artifact", dst.getArt()->artType->getIconIndex()));
CCS->curh->dragAndDropCursor("artifact", dst.getArt()->artType->getIconIndex());
}
updateParentWindow();

View File

@ -15,7 +15,7 @@
#include "../gui/CAnimation.h"
#include "../gui/SDL_Pixels.h"
#include "../gui/CGuiHandler.h"
#include "../gui/CCursorHandler.h"
#include "../gui/CursorHandler.h"
#include "../gui/ColorFilter.h"
#include "../battle/BattleInterface.h"

View File

@ -188,7 +188,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
aw->arts->markPossibleSlots(art);
//aw->arts->commonInfo->dst.AOH = aw->arts;
CCS->curh->dragAndDropCursor(std::make_unique<CAnimImage>("artifact", art->artType->iconIndex));
CCS->curh->dragAndDropCursor("artifact", art->artType->iconIndex);
aw->arts->artifactsOnAltar.erase(art);
setID(-1);