瀏覽代碼

Existing software cursor logic is now in a separate class

Ivan Savenko 2 年之前
父節點
當前提交
9971bdca1b
共有 5 個文件被更改,包括 153 次插入109 次删除
  1. 106 79
      client/gui/CursorHandler.cpp
  2. 41 24
      client/gui/CursorHandler.h
  3. 4 4
      client/widgets/CArtifactHolder.cpp
  4. 1 1
      client/widgets/Images.cpp
  5. 1 1
      client/windows/CTradeWindow.cpp

+ 106 - 79
client/gui/CursorHandler.cpp

@@ -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 = image;
+	cursorSW->setImage(getCurrentImage(), getPivotOffset());
+}
+
+void CursorHandler::dragAndDropCursor (std::string path, size_t index)
 {
-	dndObject = std::move(object);
-	if(dndObject)
-		replaceBuffer(dndObject.get());
-	else
-		replaceBuffer(currentCursor);
+	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();
-
-	Point renderPos = pos;
+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();
 
-	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);
+}
+
+void CursorSoftware::updateTexture()
+{
+	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;
 }
 
-CursorHandler::~CursorHandler()
+CursorSoftware::CursorSoftware():
+	cursorTexture(nullptr),
+	cursorSurface(nullptr),
+	needUpdate(false),
+	pivot(0,0)
 {
-	if(buffer)
-		SDL_FreeSurface(buffer);
+	SDL_ShowCursor(SDL_DISABLE);
+}
+
+CursorSoftware::~CursorSoftware()
+{
+	if(cursorTexture)
+		SDL_DestroyTexture(cursorTexture);
+
+	if (cursorSurface)
+		SDL_FreeSurface(cursorSurface);
 
-	if(cursorLayer)
-		SDL_DestroyTexture(cursorLayer);
 }

+ 41 - 24
client/gui/CursorHandler.h

@@ -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
 	};
 }
 
-/// handles mouse cursor
-class CursorHandler final
+class CursorHardware
+{
+	//TODO
+};
+
+class CursorSoftware
 {
+	std::shared_ptr<IImage> cursorImage;
+
+	SDL_Texture * cursorTexture;
+	SDL_Surface * cursorSurface;
+
+	Point pos;
+	Point pivot;
 	bool needUpdate;
-	SDL_Texture * cursorLayer;
 
-	SDL_Surface * buffer;
-	CAnimImage * currentCursor;
+	void createTexture(const Point & dimensions);
+	void updateTexture();
+public:
+	CursorSoftware();
+	~CursorSoftware();
 
-	std::unique_ptr<CAnimImage> dndObject; //if set, overrides currentCursor
+	void setImage(std::shared_ptr<IImage> image, const Point & pivotOffset);
+	void setCursorPosition( const Point & newPos );
 
-	std::array<std::unique_ptr<CAnimImage>, 4> cursors;
+	void render();
+	void setVisible(bool on);
+};
 
-	bool showing;
+/// handles mouse cursor
+class CursorHandler final
+{
+	std::shared_ptr<IImage> dndObject; //if set, overrides currentCursor
 
-	void clearBuffer();
-	void updateBuffer(CIntObject * payload);
-	void replaceBuffer(CIntObject * payload);
+	std::array<std::unique_ptr<CAnimation>, 4> cursors;
 
-	void updateTexture();
+	bool showing;
 
 	/// 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;

+ 4 - 4
client/widgets/CArtifactHolder.cpp

@@ -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();

+ 1 - 1
client/widgets/Images.cpp

@@ -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"

+ 1 - 1
client/windows/CTradeWindow.cpp

@@ -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);