...
This commit is contained in:
parent
af80e71d17
commit
167c433a59
@ -1,5 +1,236 @@
|
|||||||
//
|
|
||||||
// Created by JIBUM HAN on 2025. 8. 28..
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "AnimationStrategy.h"
|
#include "AnimationStrategy.h"
|
||||||
|
#include "Renderer.h" // Renderer의 그리기 헬퍼 함수들을 사용하기 위해 포함
|
||||||
|
#include <algorithm> // for std::max, std::clamp
|
||||||
|
#include <vector>
|
||||||
|
#include <numeric>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// --- PAN (왕복 이동) 애니메이션 ---
|
||||||
|
// ====================================================================
|
||||||
|
class PanAnimation : public AnimationStrategy {
|
||||||
|
public:
|
||||||
|
PanAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
||||||
|
|
||||||
|
void reset() override {
|
||||||
|
offsetX_ = 0.0f;
|
||||||
|
offsetY_ = 0.0f;
|
||||||
|
cycleComplete_ = false;
|
||||||
|
xDirection_ = 1;
|
||||||
|
yDirection_ = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||||
|
// 1. 애니메이션이 이미 끝났으면 더 이상 계산하지 않음
|
||||||
|
if (cycleComplete_) {
|
||||||
|
// 마지막 위치에 고정하여 그림
|
||||||
|
renderer->drawMedia(buffer, media, 1.0f, offsetX_, offsetY_, getBaseScale(media, surfaceWidth, surfaceHeight));
|
||||||
|
return cycleComplete_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Pan 모드에 필요한 overflow(화면 밖으로 넘친 영역) 계산
|
||||||
|
float overflowX = 0.0f, overflowY = 0.0f;
|
||||||
|
float scale = getBaseScale(media, surfaceWidth, surfaceHeight);
|
||||||
|
float mediaW = static_cast<float>(media.getWidth());
|
||||||
|
float mediaH = static_cast<float>(media.getHeight());
|
||||||
|
if ((mediaW / mediaH) > ((float)surfaceWidth / surfaceHeight)) {
|
||||||
|
overflowX = std::max(0.0f, mediaW * scale - surfaceWidth);
|
||||||
|
} else {
|
||||||
|
overflowY = std::max(0.0f, mediaH * scale - surfaceHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 좌표 업데이트
|
||||||
|
bool xDone = (overflowX <= 0);
|
||||||
|
bool yDone = (overflowY <= 0);
|
||||||
|
|
||||||
|
if (overflowX > 0) {
|
||||||
|
offsetX_ += animationSpeed_ * xDirection_;
|
||||||
|
if (xDirection_ == 1 && offsetX_ >= overflowX) { offsetX_ = overflowX; xDirection_ = -1; }
|
||||||
|
else if (xDirection_ == -1 && offsetX_ <= 0) { offsetX_ = 0; xDirection_ = 1; xDone = true; }
|
||||||
|
}
|
||||||
|
if (overflowY > 0) {
|
||||||
|
offsetY_ += animationSpeed_ * yDirection_;
|
||||||
|
if (yDirection_ == 1 && offsetY_ >= overflowY) { offsetY_ = overflowY; yDirection_ = -1; }
|
||||||
|
else if (yDirection_ == -1 && offsetY_ <= 0) { offsetY_ = 0; yDirection_ = 1; yDone = true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. X, Y축 왕복이 모두 끝났는지 확인
|
||||||
|
if (xDone && yDone) {
|
||||||
|
cycleComplete_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 계산된 최종 좌표로 그림
|
||||||
|
renderer->drawMedia(buffer, media, 1.0f, offsetX_, offsetY_, scale);
|
||||||
|
|
||||||
|
return cycleComplete_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float offsetX_, offsetY_;
|
||||||
|
int xDirection_, yDirection_;
|
||||||
|
bool cycleComplete_;
|
||||||
|
|
||||||
|
float getBaseScale(MediaAsset& media, int surfaceWidth, int surfaceHeight) {
|
||||||
|
float scale;
|
||||||
|
if ((static_cast<float>(media.getWidth()) / media.getHeight()) > ((float)surfaceWidth / surfaceHeight)) {
|
||||||
|
scale = (float)surfaceHeight / media.getHeight();
|
||||||
|
} else {
|
||||||
|
scale = (float)surfaceWidth / media.getWidth();
|
||||||
|
}
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// --- PAN_ONE_WAY (편도 이동) 애니메이션 ---
|
||||||
|
// ====================================================================
|
||||||
|
class PanOneWayAnimation : public AnimationStrategy {
|
||||||
|
public:
|
||||||
|
PanOneWayAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
||||||
|
|
||||||
|
void reset() override {
|
||||||
|
offsetX_ = 0.0f;
|
||||||
|
offsetY_ = 0.0f;
|
||||||
|
cycleComplete_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||||
|
if (cycleComplete_) {
|
||||||
|
renderer->drawMedia(buffer, media, 1.0f, offsetX_, offsetY_, getBaseScale(media, surfaceWidth, surfaceHeight));
|
||||||
|
return cycleComplete_;
|
||||||
|
}
|
||||||
|
|
||||||
|
float overflowX = 0.0f, overflowY = 0.0f;
|
||||||
|
float scale = getBaseScale(media, surfaceWidth, surfaceHeight);
|
||||||
|
float mediaW = static_cast<float>(media.getWidth());
|
||||||
|
float mediaH = static_cast<float>(media.getHeight());
|
||||||
|
if ((mediaW / mediaH) > ((float)surfaceWidth / surfaceHeight)) {
|
||||||
|
overflowX = std::max(0.0f, mediaW * scale - surfaceWidth);
|
||||||
|
} else {
|
||||||
|
overflowY = std::max(0.0f, mediaH * scale - surfaceHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xReachedEnd = (overflowX <= 0);
|
||||||
|
bool yReachedEnd = (overflowY <= 0);
|
||||||
|
|
||||||
|
if (overflowX > 0) {
|
||||||
|
offsetX_ += animationSpeed_;
|
||||||
|
if (offsetX_ >= overflowX) { offsetX_ = overflowX; xReachedEnd = true; }
|
||||||
|
}
|
||||||
|
if (overflowY > 0) {
|
||||||
|
offsetY_ += animationSpeed_;
|
||||||
|
if (offsetY_ >= overflowY) { offsetY_ = overflowY; yReachedEnd = true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xReachedEnd && yReachedEnd) {
|
||||||
|
cycleComplete_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer->drawMedia(buffer, media, 1.0f, offsetX_, offsetY_, scale);
|
||||||
|
return cycleComplete_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float offsetX_, offsetY_;
|
||||||
|
bool cycleComplete_;
|
||||||
|
|
||||||
|
float getBaseScale(MediaAsset& media, int surfaceWidth, int surfaceHeight) {
|
||||||
|
// (PanAnimation과 중복되지만, 각 클래스의 독립성을 위해 포함)
|
||||||
|
float scale;
|
||||||
|
if ((static_cast<float>(media.getWidth()) / media.getHeight()) > ((float)surfaceWidth / surfaceHeight)) {
|
||||||
|
scale = (float)surfaceHeight / media.getHeight();
|
||||||
|
} else {
|
||||||
|
scale = (float)surfaceWidth / media.getWidth();
|
||||||
|
}
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// --- ZOOM 애니메이션 ---
|
||||||
|
// ====================================================================
|
||||||
|
class ZoomAnimation : public AnimationStrategy {
|
||||||
|
public:
|
||||||
|
ZoomAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
||||||
|
|
||||||
|
void reset() override {
|
||||||
|
scaleMultiplier_ = 1.0f;
|
||||||
|
cycleComplete_ = false;
|
||||||
|
zoomDirection_ = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||||
|
if (!cycleComplete_) {
|
||||||
|
scaleMultiplier_ += 0.0005f * animationSpeed_ * zoomDirection_;
|
||||||
|
if (zoomDirection_ == 1 && scaleMultiplier_ >= 1.2f) { scaleMultiplier_ = 1.2f; zoomDirection_ = -1; }
|
||||||
|
else if (zoomDirection_ == -1 && scaleMultiplier_ <= 1.0f) { scaleMultiplier_ = 1.0f; zoomDirection_ = 1; cycleComplete_ = true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZOOM은 중앙 정렬을 기본으로 함
|
||||||
|
float baseScale, baseOffsetX, baseOffsetY;
|
||||||
|
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||||
|
renderer->drawMedia(buffer, media, 1.0f, baseOffsetX, baseOffsetY, baseScale * scaleMultiplier_);
|
||||||
|
|
||||||
|
return cycleComplete_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float scaleMultiplier_;
|
||||||
|
int zoomDirection_;
|
||||||
|
bool cycleComplete_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// --- PAGE_TURN (대기) 애니메이션 ---
|
||||||
|
// ====================================================================
|
||||||
|
class PageTurnAnimation : public AnimationStrategy {
|
||||||
|
public:
|
||||||
|
PageTurnAnimation(float speed, long long delay) : AnimationStrategy(speed), delayMs_(delay) { reset(); }
|
||||||
|
|
||||||
|
void reset() override {
|
||||||
|
cycleComplete_ = false;
|
||||||
|
startTime_ = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||||
|
if (!cycleComplete_) {
|
||||||
|
long long elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startTime_).count();
|
||||||
|
if (elapsed >= delayMs_) {
|
||||||
|
cycleComplete_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 대기하는 동안 중앙에 고정된 이미지를 그림
|
||||||
|
float baseScale, baseOffsetX, baseOffsetY;
|
||||||
|
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||||
|
renderer->drawMedia(buffer, media, 1.0f, baseOffsetX, baseOffsetY, baseScale);
|
||||||
|
|
||||||
|
return cycleComplete_;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
long long delayMs_;
|
||||||
|
std::chrono::steady_clock::time_point startTime_;
|
||||||
|
bool cycleComplete_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// --- NONE (애니메이션 없음) ---
|
||||||
|
// ====================================================================
|
||||||
|
class NoneAnimation : public AnimationStrategy {
|
||||||
|
public:
|
||||||
|
NoneAnimation(float speed) : AnimationStrategy(speed) {}
|
||||||
|
void reset() override {} // 아무것도 안 함
|
||||||
|
|
||||||
|
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||||
|
// 중앙에 고정된 이미지만 그림
|
||||||
|
float baseScale, baseOffsetX, baseOffsetY;
|
||||||
|
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||||
|
renderer->drawMedia(buffer, media, 1.0f, baseOffsetX, baseOffsetY, baseScale);
|
||||||
|
|
||||||
|
return true; // 즉시 완료
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,30 +1,22 @@
|
|||||||
//
|
|
||||||
// Created by JIBUM HAN on 2025. 8. 28..
|
|
||||||
//
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <chrono>
|
#include <android/native_window.h>
|
||||||
|
#include "MediaAsset.h"
|
||||||
|
|
||||||
// 애니메이션의 현재 상태를 담을 구조체
|
class Renderer; // 전방 선언
|
||||||
struct AnimationState {
|
|
||||||
float offsetX = 0.0f;
|
|
||||||
float offsetY = 0.0f;
|
|
||||||
float scale = 1.0f;
|
|
||||||
bool cycleComplete = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 모든 '전문 요리사'의 기반이 될 추상 클래스
|
|
||||||
class AnimationStrategy {
|
class AnimationStrategy {
|
||||||
public:
|
public:
|
||||||
virtual ~AnimationStrategy() = default;
|
virtual ~AnimationStrategy() = default;
|
||||||
|
|
||||||
// 매 프레임마다 호출되어 애니메이션 상태를 업데이트하고 반환
|
/**
|
||||||
virtual AnimationState update(float overflowX, float overflowY) = 0;
|
* @brief 애니메이션 효과를 직접 렌더링 버퍼에 그립니다.
|
||||||
|
* @return 애니메이션 한 사이클이 완료되었으면 true
|
||||||
|
*/
|
||||||
|
virtual bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) = 0;
|
||||||
|
|
||||||
// 애니메이션 상태를 처음으로 리셋
|
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// 생성자에서 애니메이션 속도를 받아 저장
|
|
||||||
AnimationStrategy(float speed) : animationSpeed_(speed) {}
|
AnimationStrategy(float speed) : animationSpeed_(speed) {}
|
||||||
float animationSpeed_;
|
float animationSpeed_;
|
||||||
};
|
};
|
||||||
@ -1,17 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by JIBUM HAN on 2025. 8. 28..
|
|
||||||
//
|
|
||||||
#include "AnimationStrategy.h"
|
|
||||||
#include <algorithm> // for std::max
|
|
||||||
|
|
||||||
#ifndef LUNARLAUNCHER_NONEANIMATION_H
|
|
||||||
#define LUNARLAUNCHER_NONEANIMATION_H
|
|
||||||
class NoneAnimation : public AnimationStrategy {
|
|
||||||
public:
|
|
||||||
NoneAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
|
||||||
void reset() override { state_.cycleComplete = true; }
|
|
||||||
AnimationState update(float, float) override { return state_; }
|
|
||||||
private:
|
|
||||||
AnimationState state_;
|
|
||||||
};
|
|
||||||
#endif //LUNARLAUNCHER_NONEANIMATION_H
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by JIBUM HAN on 2025. 8. 28..
|
|
||||||
//
|
|
||||||
#include "AnimationStrategy.h"
|
|
||||||
#include <algorithm> // for std::max
|
|
||||||
|
|
||||||
#ifndef LUNARLAUNCHER_PAGETURNANIMATION_H
|
|
||||||
#define LUNARLAUNCHER_PAGETURNANIMATION_H
|
|
||||||
|
|
||||||
// --- PAGE_TURN (대기 후 페이드) 애니메이션 ---
|
|
||||||
class PageTurnAnimation : public AnimationStrategy {
|
|
||||||
public:
|
|
||||||
PageTurnAnimation(float speed, long long delay) : AnimationStrategy(speed), delayMs_(delay) { reset(); }
|
|
||||||
|
|
||||||
void reset() override {
|
|
||||||
state_.cycleComplete = false;
|
|
||||||
startTime_ = std::chrono::steady_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationState update(float, float) override {
|
|
||||||
if (state_.cycleComplete) return state_;
|
|
||||||
|
|
||||||
long long elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startTime_).count();
|
|
||||||
if (elapsed >= delayMs_) {
|
|
||||||
state_.cycleComplete = true;
|
|
||||||
}
|
|
||||||
return state_;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
AnimationState state_;
|
|
||||||
long long delayMs_;
|
|
||||||
std::chrono::steady_clock::time_point startTime_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //LUNARLAUNCHER_PAGETURNANIMATION_H
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by JIBUM HAN on 2025. 8. 28..
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef LUNARLAUNCHER_PANANIMATION_H
|
|
||||||
#define LUNARLAUNCHER_PANANIMATION_H
|
|
||||||
#include "AnimationStrategy.h"
|
|
||||||
#include <algorithm> // for std::max
|
|
||||||
|
|
||||||
// --- PAN (왕복) 애니메이션 ---
|
|
||||||
class PanAnimation : public AnimationStrategy {
|
|
||||||
public:
|
|
||||||
PanAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
|
||||||
|
|
||||||
void reset() override {
|
|
||||||
state_.offsetX = 0.0f;
|
|
||||||
state_.offsetY = 0.0f;
|
|
||||||
state_.cycleComplete = false;
|
|
||||||
xDirection_ = 1;
|
|
||||||
yDirection_ = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationState update(float overflowX, float overflowY) override {
|
|
||||||
if (state_.cycleComplete) return state_;
|
|
||||||
|
|
||||||
bool xDone = (overflowX <= 0);
|
|
||||||
bool yDone = (overflowY <= 0);
|
|
||||||
|
|
||||||
if (overflowX > 0) {
|
|
||||||
state_.offsetX += animationSpeed_ * xDirection_;
|
|
||||||
if (xDirection_ == 1 && state_.offsetX >= overflowX) { state_.offsetX = overflowX; xDirection_ = -1; }
|
|
||||||
else if (xDirection_ == -1 && state_.offsetX <= 0) { state_.offsetX = 0; xDirection_ = 1; xDone = true; }
|
|
||||||
}
|
|
||||||
if (overflowY > 0) {
|
|
||||||
state_.offsetY += animationSpeed_ * yDirection_;
|
|
||||||
if (yDirection_ == 1 && state_.offsetY >= overflowY) { state_.offsetY = overflowY; yDirection_ = -1; }
|
|
||||||
else if (yDirection_ == -1 && state_.offsetY <= 0) { state_.offsetY = 0; yDirection_ = 1; yDone = true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xDone && yDone) state_.cycleComplete = true;
|
|
||||||
return state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
AnimationState state_;
|
|
||||||
int xDirection_, yDirection_;
|
|
||||||
};
|
|
||||||
#endif //LUNARLAUNCHER_PANANIMATION_H
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by JIBUM HAN on 2025. 8. 28..
|
|
||||||
//
|
|
||||||
#include "AnimationStrategy.h"
|
|
||||||
#include <algorithm> // for std::max
|
|
||||||
|
|
||||||
#ifndef LUNARLAUNCHER_PANONEWAYANIMATION_H
|
|
||||||
#define LUNARLAUNCHER_PANONEWAYANIMATION_H
|
|
||||||
// --- ⬇️ 새로운 PAN_ONE_WAY (편도) 애니메이션 클래스 추가 ⬇️ ---
|
|
||||||
class PanOneWayAnimation : public AnimationStrategy {
|
|
||||||
public:
|
|
||||||
PanOneWayAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
|
||||||
|
|
||||||
void reset() override {
|
|
||||||
state_.offsetX = 0.0f;
|
|
||||||
state_.offsetY = 0.0f;
|
|
||||||
state_.cycleComplete = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationState update(float overflowX, float overflowY) override {
|
|
||||||
if (state_.cycleComplete) return state_;
|
|
||||||
|
|
||||||
bool xReachedEnd = (overflowX <= 0);
|
|
||||||
bool yReachedEnd = (overflowY <= 0);
|
|
||||||
|
|
||||||
if (overflowX > 0) {
|
|
||||||
state_.offsetX += animationSpeed_; // 항상 정방향(+)으로만 이동
|
|
||||||
if (state_.offsetX >= overflowX) {
|
|
||||||
state_.offsetX = overflowX; // 끝에 도달하면 멈춤
|
|
||||||
xReachedEnd = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overflowY > 0) {
|
|
||||||
state_.offsetY += animationSpeed_; // 항상 정방향(+)으로만 이동
|
|
||||||
if (state_.offsetY >= overflowY) {
|
|
||||||
state_.offsetY = overflowY; // 끝에 도달하면 멈춤
|
|
||||||
yReachedEnd = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// X축과 Y축 이동이 모두 끝났다면 사이클 완료
|
|
||||||
if (xReachedEnd && yReachedEnd) {
|
|
||||||
state_.cycleComplete = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
AnimationState state_;
|
|
||||||
};
|
|
||||||
#endif //LUNARLAUNCHER_PANONEWAYANIMATION_H
|
|
||||||
@ -1,10 +1,6 @@
|
|||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "AnimationStrategy.cpp"
|
#include "AnimationStrategy.cpp"
|
||||||
#include "TransitionStrategy.cpp"
|
#include "TransitionStrategy.cpp"
|
||||||
#include "NoneAnimation.h"
|
|
||||||
#include "PageTurnAnimation.h"
|
|
||||||
#include "PanAnimation.h"
|
|
||||||
#include "PanOneWayAnimation.h"
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -107,62 +103,47 @@ void Renderer::determineActiveAnimationMode() {
|
|||||||
// ====================================================================
|
// ====================================================================
|
||||||
|
|
||||||
void Renderer::handleAnimationState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight) {
|
void Renderer::handleAnimationState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight) {
|
||||||
AnimationState animState;
|
// 안전장치: 애니메이션 전문가가 고용되지 않았다면 작업을 중단
|
||||||
if (animationStrategy_) {
|
if (!animationStrategy_) {
|
||||||
float overflowX = 0.0f, overflowY = 0.0f;
|
// 이 경우엔 그냥 검은 화면만 그림
|
||||||
if (activeAnimationMode_ == AnimationMode::PAN || activeAnimationMode_ == AnimationMode::PAN_ONE_WAY) {
|
memset(buffer.bits, 0, buffer.stride * buffer.height * sizeof(uint32_t));
|
||||||
float mediaW = static_cast<float>(currentMedia_.getWidth());
|
return;
|
||||||
float mediaH = static_cast<float>(currentMedia_.getHeight());
|
|
||||||
if ((mediaW / mediaH) > (static_cast<float>(surfaceWidth) / surfaceHeight)) {
|
|
||||||
float scale = static_cast<float>(surfaceHeight) / mediaH;
|
|
||||||
overflowX = std::max(0.0f, mediaW * scale - surfaceWidth);
|
|
||||||
} else {
|
|
||||||
float scale = static_cast<float>(surfaceWidth) / mediaW;
|
|
||||||
overflowY = std::max(0.0f, mediaH * scale - surfaceHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
animState = animationStrategy_->update(overflowX, overflowY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buffer.bits, 0, buffer.stride * buffer.height * sizeof(uint32_t));
|
// 1. 위임: 현재 애니메이션 전문가에게 모든 계산과 그리기를 맡기고, 완료 여부만 보고받음
|
||||||
float finalOffsetX, finalOffsetY, finalScale;
|
// (이 execute 함수 내부에서 배경을 지우고, 좌표를 계산하고, drawMedia를 호출하는 모든 작업을 수행함)
|
||||||
if (activeAnimationMode_ == AnimationMode::PAN || activeAnimationMode_ == AnimationMode::PAN_ONE_WAY) {
|
bool isCycleComplete = animationStrategy_->execute(this, buffer, currentMedia_, surfaceWidth, surfaceHeight);
|
||||||
float scale;
|
|
||||||
if ((static_cast<float>(currentMedia_.getWidth()) / currentMedia_.getHeight()) > (static_cast<float>(surfaceWidth) / surfaceHeight)) {
|
|
||||||
scale = static_cast<float>(surfaceHeight) / currentMedia_.getHeight();
|
|
||||||
} else {
|
|
||||||
scale = static_cast<float>(surfaceWidth) / currentMedia_.getWidth();
|
|
||||||
}
|
|
||||||
finalScale = scale * animState.scale;
|
|
||||||
finalOffsetX = animState.offsetX;
|
|
||||||
finalOffsetY = animState.offsetY;
|
|
||||||
} else {
|
|
||||||
float baseScale, baseOffsetX, baseOffsetY;
|
|
||||||
calculateFitScaleAndOffset(currentMedia_, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
|
||||||
finalScale = baseScale * animState.scale;
|
|
||||||
finalOffsetX = baseOffsetX + animState.offsetX;
|
|
||||||
finalOffsetY = baseOffsetY + animState.offsetY;
|
|
||||||
}
|
|
||||||
drawMedia(buffer, currentMedia_, 1.0f, finalOffsetX, finalOffsetY, finalScale);
|
|
||||||
|
|
||||||
if (animState.cycleComplete && nextMedia_.isValid()) {
|
|
||||||
|
// 2. 상태 전환: 애니메이션이 끝났고, 다음 미디어가 대기 중이라면 '전환' 상태로 넘어감
|
||||||
|
if (isCycleComplete && nextMedia_.isValid()) {
|
||||||
currentState_ = RenderState::TRANSITIONING;
|
currentState_ = RenderState::TRANSITIONING;
|
||||||
transitionStartTime_ = std::chrono::steady_clock::now();
|
transitionStartTime_ = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
// 사용자가 설정한 전환 모드를 확인
|
||||||
TransitionMode transModeToUse = configuredTransitionMode_;
|
TransitionMode transModeToUse = configuredTransitionMode_;
|
||||||
if (transModeToUse == TransitionMode::RANDOM) {
|
if (transModeToUse == TransitionMode::RANDOM) {
|
||||||
|
// RANDOM일 경우, FADE, SLIDE, MOSAIC 중에서 무작위로 선택
|
||||||
std::uniform_int_distribution<int> dist(0, 2);
|
std::uniform_int_distribution<int> dist(0, 2);
|
||||||
transModeToUse = static_cast<TransitionMode>(dist(randomEngine_));
|
int randomChoice = dist(randomEngine_);
|
||||||
|
if (randomChoice == 0) transModeToUse = TransitionMode::FADE;
|
||||||
|
else if (randomChoice == 1) transModeToUse = TransitionMode::SLIDE;
|
||||||
|
else transModeToUse = TransitionMode::MOSAIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 결정된 모드에 맞는 '전환 전문가' 객체를 생성
|
||||||
if (transModeToUse == TransitionMode::SLIDE) {
|
if (transModeToUse == TransitionMode::SLIDE) {
|
||||||
transitionStrategy_ = std::make_unique<SlideTransition>(fadeDurationMs_, surfaceWidth);
|
transitionStrategy_ = std::make_unique<SlideTransition>(fadeDurationMs_, surfaceWidth);
|
||||||
} else if (transModeToUse == TransitionMode::MOSAIC) {
|
} else if (transModeToUse == TransitionMode::MOSAIC) {
|
||||||
transitionStrategy_ = std::make_unique<MosaicTransition>(fadeDurationMs_, 20, 32, randomEngine_);
|
transitionStrategy_ = std::make_unique<MosaicTransition>(fadeDurationMs_, 20, 32, randomEngine_);
|
||||||
} else {
|
} else { // 기본값은 FADE
|
||||||
transitionStrategy_ = std::make_unique<FadeTransition>(fadeDurationMs_);
|
transitionStrategy_ = std::make_unique<FadeTransition>(fadeDurationMs_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 새로운 전환 전문가의 상태를 초기화
|
||||||
if(transitionStrategy_) transitionStrategy_->reset();
|
if(transitionStrategy_) transitionStrategy_->reset();
|
||||||
|
|
||||||
|
LOGI("Animation complete. Switching to TRANSITIONING state.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +156,6 @@ void Renderer::handleTransitionState(ANativeWindow_Buffer& buffer, int surfaceWi
|
|||||||
|
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
long long elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - transitionStartTime_).count();
|
long long elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - transitionStartTime_).count();
|
||||||
// 1. 상태 보고: isComplete()를 호출해서 끝났는지 "물어보기만" 함
|
|
||||||
bool isComplete = transitionStrategy_->isComplete(elapsed);
|
bool isComplete = transitionStrategy_->isComplete(elapsed);
|
||||||
|
|
||||||
transitionStrategy_->execute(this, buffer, currentMedia_, nextMedia_, elapsed);
|
transitionStrategy_->execute(this, buffer, currentMedia_, nextMedia_, elapsed);
|
||||||
@ -183,6 +163,7 @@ void Renderer::handleTransitionState(ANativeWindow_Buffer& buffer, int surfaceWi
|
|||||||
if (isComplete) {
|
if (isComplete) {
|
||||||
currentMedia_ = std::move(nextMedia_);
|
currentMedia_ = std::move(nextMedia_);
|
||||||
currentState_ = RenderState::ANIMATING;
|
currentState_ = RenderState::ANIMATING;
|
||||||
|
animationCycleComplete_ = false; // 새 미디어의 애니메이션 시작 준비
|
||||||
determineActiveAnimationMode();
|
determineActiveAnimationMode();
|
||||||
if(animationStrategy_) animationStrategy_->reset();
|
if(animationStrategy_) animationStrategy_->reset();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,7 +63,7 @@ private:
|
|||||||
TRANSITIONING
|
TRANSITIONING
|
||||||
};
|
};
|
||||||
RenderState currentState_ = RenderState::ANIMATING;
|
RenderState currentState_ = RenderState::ANIMATING;
|
||||||
|
bool animationCycleComplete_ = false; // <-- 이 플래그가 다시 필요
|
||||||
// --- 상태별 처리를 위한 private 핸들러 함수 ---
|
// --- 상태별 처리를 위한 private 핸들러 함수 ---
|
||||||
void handleAnimationState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight);
|
void handleAnimationState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight);
|
||||||
void handleTransitionState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight);
|
void handleTransitionState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight);
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by JIBUM HAN on 2025. 8. 28..
|
|
||||||
//
|
|
||||||
#include "AnimationStrategy.h"
|
|
||||||
#include <algorithm> // for std::max
|
|
||||||
#ifndef LUNARLAUNCHER_ZOOMANIMATION_H
|
|
||||||
#define LUNARLAUNCHER_ZOOMANIMATION_H
|
|
||||||
// --- ZOOM 애니메이션 ---
|
|
||||||
class ZoomAnimation : public AnimationStrategy {
|
|
||||||
public:
|
|
||||||
ZoomAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
|
||||||
|
|
||||||
void reset() override {
|
|
||||||
state_.scale = 1.0f;
|
|
||||||
state_.cycleComplete = false;
|
|
||||||
zoomDirection_ = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationState update(float, float) override {
|
|
||||||
if (state_.cycleComplete) return state_;
|
|
||||||
|
|
||||||
state_.scale += 0.0005f * animationSpeed_ * zoomDirection_;
|
|
||||||
if (zoomDirection_ == 1 && state_.scale >= 1.2f) { state_.scale = 1.2f; zoomDirection_ = -1; }
|
|
||||||
else if (zoomDirection_ == -1 && state_.scale <= 1.0f) { state_.scale = 1.0f; zoomDirection_ = 1; state_.cycleComplete = true; }
|
|
||||||
|
|
||||||
return state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
AnimationState state_;
|
|
||||||
int zoomDirection_;
|
|
||||||
};
|
|
||||||
#endif //LUNARLAUNCHER_ZOOMANIMATION_H
|
|
||||||
Loading…
x
Reference in New Issue
Block a user