컴퓨터 그래픽스/OpenGL

#5 tinylender 개발일지 : 상태 머신 적용

san10 2024. 5. 12. 19:11

GUI를 만들었으니 이제 입력에 따라 상태가 변화해야한다.

그래서 현재 상태에 따라 동작하게끔 상태 머신을 만들었다.

 

Context

class Context{
    public:
        Context(IState* layerState, IState* dotState, IState* lineState, IState* surfaceState);
        void Transition(eUIState state);
        void HandleState();
        eUIState GetState() const {return mState;}

    private:
        eUIState mState;
        IState* mCurrentState=NULL;
        IState* mLayerState;
        IState* mDotState;
        IState* mLineState;
        IState* mSurfaceState;

};

 

각 상태들을 가지고 관리해주는 Context를 만들었다.

 

void Context::Transition(eUIState state)
{
    switch (state)
    {
        case EMPTY:
            mState=state;
            mCurrentState = NULL;
            break;

        case LAYER:
            mState=state;
            mCurrentState = mLayerState;
            break;

        case DOT:
            mState=state;
            mCurrentState = mDotState;
            break;

        case LINE:
            mState=state;
            mCurrentState = mLineState;
            break;

        case SURFACE:
            mState=state;
            mCurrentState = mSurfaceState;
            break;
        
        default:
            break;
    }
}

Transition()은 내가 원하는 상태가 될 수 있도록 현재 상태를 전환시켜준다.

아직 상태 구조도같은건 그리지 않았기에

입력으로 들어온 값으로 바로 전환해준다.

 

void Context::HandleState(){
    if(mCurrentState!=NULL)
         mCurrentState->Handle();
}

HandleState()는 현재 상태가 계속 작동시키는 역할이다.

HandleState()는 메인 루프에서 계속 돌면서 현재 상태의 Handle()을 호출한다.

 

IState

class IState{
    public:
        virtual ~IState() {};
        virtual void Handle() =0;
};

상태를 가지는 객체들은 IState를 상속받아서 구현한다.

위에서 설명했듯이 Handle은 현재 나의 상태일때 객체가 해야 하는 일을 구현한다.

 

 

ModifyVertex

https://san10.tistory.com/54?category=1088990

 

#1 gulender 개발일지 : 기본적인 조작, 버텍스 수정 기능

우선 openGL에 대한 기본적인 지식을 learnOpenGL 이라는 사이트에서 공부했다. https://learnopengl.com/ Learn OpenGL, extensive tutorial resource for learning Modern OpenGL Welcome to OpenGL Welcome to the online book for learning OpenG

san10.tistory.com

이전에 버텍스를 조작하는 기능을 만들었는데,

이 기능을 객체로 따로 빼고, 상태가 될수 있게 만들었다.

 

class ModifyVertex:public IPressedDown,public IPressed, public IPressedUp,public IState{
    public:
        void OnPointer(float xpos, float ypos,float xdelta,float ydelta) override;
        void OnPointerDown(float xpos, float ypos,float xdelta,float ydelta) override;
        void OnPointerUp(float xpos, float ypos,float xdelta,float ydelta) override;
        void Handle() override;

    private:
        bool bPushed=false;
        bool bFindVertex = false;
        float mDeltaX, mDeltaY;
        int mSelectedIdx=0;
        glm::vec2 coordinatelocalToScreen(float x,float y, float z);
        bool searchVertex(float xpos, float ypos);
};

코드 내용은 저번에 작성했던 것과 비슷하다

 

이 내용들을 바탕으로 메인에 구현해준다.

ModifyVertex* layerState = new ModifyVertex(); //아직 ModifyVertex만 구현해서 임시로 땜빵
ModifyVertex* dotState = new ModifyVertex();
ModifyVertex* lineState = new ModifyVertex();
ModifyVertex* surfaceState = new ModifyVertex();

eventSystem->AddPressed(dotState);
eventSystem->AddPressedDown(dotState);
eventSystem->AddPressedUp(dotState);

Context* context = new Context(layerState,dotState,lineState,surfaceState);

while (!glfwWindowShouldClose(window)){
     context->HandleState();
}

 

그리고 만들어놨던 버튼에 버튼을 누르면 상태가 전환되도록 콜백을 추가했다.

Button* dotBtn = new Button(glm::vec3(-0.701058201058201f,0.8065173116089613f,0.0f)
    ,0.08994708994708994f,0.1384928716904277f,"resource/dotIcon.jpg",eImageType::JPG);
    
auto dotBtnCallback =[&dotBtn,&context](double xpos, double ypos){
    dotBtn->Pushed();

    if(dotBtn->GetPushed() == true){
        dotBtn->SetTexture("resource/dotIconPushed.png",eImageType::PNG);
        context->Transition(eUIState::DOT);
    }
    else{
        dotBtn->SetTexture("resource/dotIcon.jpg",eImageType::JPG);
        context->Transition(eUIState::EMPTY);
    }
};

dotBtn->SetbuttonCallback(std::function<void(double, double)>(dotBtnCallback));
canvas ->AddWidget(dotBtn);

 

여기까지 해주면..

 

???

이제 버튼을 눌렀을때만 기능이 실행되기는 한데

특정 버텍스만 수정이 가능하다

 

 

큐브로 실행해보니깐 그냥 잘 되는데..

어차피 이 기능은 안쓰일것 같아서..

일단은 넘어간다..

 

 

색상 변경

추가로..

색 버튼을 누르면 색상을 변경하는 기능도 추가했다

Button* purpleBtn = new Button(glm::vec3(-0.20965608465608465f,0.8065173116089613f,0.0f)
    ,0.051587301587301584f,0.0814663951120163f,"resource/Purple.png",eImageType::PNG);
auto purpleBtnCallback =[&ourShader](double xpos, double ypos){
    ourShader.use();
    glUniform3f(glGetUniformLocation(ourShader.ID,"val"),0.7f,0.3f,0.7f);
};
purpleBtn->SetbuttonCallback(std::function<void(double, double)>(purpleBtnCallback));
canvas ->AddWidget(purpleBtn);

이런 식으로 모든 색버튼에 콜백을 달아줬다.

 

그리고 색상을 바꾸는 것은

그냥 색 바꾸고 끝이기 때문에 따로 state로 만들진 않았다.

 

그리고 실행해보면..

 

사실 이 기능도 크게 의미는 없다..

하지만 색깔이 바뀌면..

기분이 조크등여 ^_^