[카테고리:] 이전 블로그

태터툴즈, 블로거닷컴, VCL WordPress 등지에서 내보낸 블로그 글들.

  • 디아블로3, 여러 스탯 공식들 기록

    스탯 계산에 대한 참고자료

    참고자료

    공격, 방어, 경험치 등:

    http://mmo-mechanics.com/swtor/forums/Thread-Diablo-3-formula-list

     우리나라에는 주로 DPS 계산기만 있는데, EHP(Effective Health Pool) 계산기도 있다
    dps 계산기: http://armadagaming.com/dpscalculator.php
    ehp 계산기: http://www.diablofans.com/topic/43712-diablo3-effective-health-pool-calculator/

    디아블로3 방어스탯 공략
    http://milky.alicecompany.co.kr/761

    게임메카 기사: 디아블로3 저항 시스템, 생존을 위한 필수 요소
    http://dia3.gamemeca.com/mecareport.php?gid=22763

  • 디아블로 3: 악마사냥꾼 불지옥 입성.

    디아블로 3: 악마사냥꾼 불지옥 입성.

    현재 모든 클래스를 다 길러보고 있는 가운데,
    두 번째로 육성한 악마사냥꾼이 불지옥에 처음으로 입성!

    저스펙이긴 하지만 뭐 차차 해결하면 되는거지.

  • C-Style Callback 함수와 클래스에 관한 스터디

    문제 제기:

    C-Style의 콜백 구조는 C++ 프로그래밍에서 큰 문제를 일으킨다. 그 문제는 콜백 함수의 인자로 들어가는 함수 포인터에는 ‘클래스 멤버 함수’는 들어갈 수가 없다는 점이다.

    보통 이러한 문제를 해결하기 위해 아예 일반 함수 콜백에 전역변수를 사용하곤 한다. 하지만, 이러한 해결은 많은 결점을 낳는다. 프로그램이 점점 작성될 수록 매우 프로그래밍하기 불편한 구조로 되어 버리기 때문이다.

    그 하나의 예로 GLUT를 이용한 프로그래밍을 들 수 있다. GLUT는 매우 사용하기 간결하고 편리하지만, 콜백 함수가 전형적인 ‘C-Style’이라 프로그램에 필요한 데이터가 전역변수로 저장되는 경우가 빈번한데, 이런 형태로 조금만 프로그램이 커져버리면 혼란스러운 전역 변수의 범벅에서 길을 잃어버리는 경우가 허다하다.

    진땀을 흘려가며 전역 변수 투성이 코드를 디버깅하며  ‘클래스를 사용할 수 있으면 참 좋을텐데’ 라고 생각해 본 적이 있는가? 그렇다면 ‘클래스 (혹은 구조체)’를 사용하면서도 C-Style의 콜백을 이용하려면 어떻게 해야 할까? 이 포스트는 그러한 방법에 대해 서술하고자 한다.

    차례:

    01 C-Style Callback

    02 Callback and Class

    03 Static Variable

    04 Data Class and Callback Class

    05 Template Callback Class

    06 GLUT Application

    07 더 다양한 스터디

  • 더 다양한 스터디

    현재까지 제안된 방법이 최선일까? 앞서 이야기하기도 했지만 절대 그렇지 않을 것이다. 더 다양한 방법이 있을 수 있을 것이다. 본 포스트에는 좀 더 나은 방법에 대해 기록하며, 그 이외의 다양한 이야기를 적어둘 것이다.

    콜백함수를 위한 템플릿을 이용한 2개의 클래스를 사용하는 것 보다 괜찮아 보이는 방법 중 하나는 ‘함수 어댑터(function adaptor)’를 사용하는 방법이다(출처).

    // binding function 제작
    #include <iostream>
    #include <cstddef>
    
    // 콜백 함수
    struct demo
    {
        void func() { std::cout << "called.n"; }
    };
    
    template <typename obj, void (obj::*xptr)() >
    struct func_bind
    {
        static obj x;
        static void call() { (x.*xptr)(); }
    };
    
    template <typename obj, void (obj::*xptr)(void) >
    obj func_bind::x;
    
    // 전역변수 콜백 함수 포인터.
    // 어떤 라이브러리 어딘가에 있다고 가정한다.
    void (*g_callback)(void) = NULL;
    
    int main(int argc, char** argv)
    {
        // 라이브러리에 우리의 콜백 함수를 등록하는 과정이라고 가정한다.
        func_bind<demo, &demo::func> bound;
    
        g_callback = bound.call;
        g_callback();    
    
        return EXIT_SUCCESS;
    }

     

    [그 외 이야기들]

    함수 어댑터

    멤버 함수를 위한 STL 함수 어댑터들이 있다.mem_fun_ref, mem_fun 들이 그것이다.

    #include <functional>
    
    demo d; // 멤버 변수를 가진 클래스
    std::mem_fun_t<void, demo>     p = std::mem_fun<void, demo>(&demo::func);
    std::mem_fun_ref_t<void, demo> r = std::mem_fun_ref<void, demo>(&demo::func);
    
    p(&d); // demo::func 멤버 함수 호출
    r(d);  // 위와 같으나 위는 객체의 포인터, 이것은 객체의 레퍼런스를 인자로 받는다.

    선언된 p나 r은 C-Style callback의 인자로는 사용할 수 없다.

    [GLUT Wrapper 등]

    • G. Stetten  과 K.Crawford는 GLUT의 C++ wrapper 인 GlutMaster를 만들었다. (홈페이지)
    • N. Stewart는 OpenGL C++ Toolkit를 공개했다. (홈페이지)

    [Function Object]

    • mem_fun, mem_fun_ptr 등은 functional 헤더에 정의되어 있다. 이 외에도 STL은 많은 함수 어댑터를 제공한다. 이들을 이용해 함수형 프로그래밍이 가능하다.
    • Boost library는 함수형 프로그래밍 뿐 아니라 C++ 프로그래밍에 있어 유용한 많은 기능을 제공한다. Boost에 대해서는 차후 따로 포스팅할 계획이다.

    차례로 돌아가기

  • GLUT Application

    GLUT의 callback 함수 매커니즘은 대표적인 C-style이고 인터넷 검색을 하면 많은 자료를 찾을 수 있다. 이는 나중에 다룰 생각이고, 이번에는 지금까지 만든 코드를 실제로 GLUT에 적용해 보도록 하겠다.

    본 예제는 M. Kilgard의 ‘A simple red cube drawn with minimal OpenGL calls.’를 바탕으로 변형한 것이다. 원본 소스는 여기서 다운로드 받을 수 있다.  GLUT는 freeglut을 사용하였다. 지금까지 차분히 따라왔다면 소스가 어떻게 구성되었는지 쉽게 감을 잡을 수 있을 것이다. 본 포스트에는 main 함수 부분만 간략하게 제시하고, 나머지 소스는 첨부 파일로 대신한다.

    #include <GL/freeglut.h>
    #include <iostream>
    #include "glut_callback.h"
    #include "box.h"
    
    int main(int argc, char** argv)
    {
        box my_box;    
    
        //box 초기화
        my_box.init_values();
    
        // 콜백될 때 함수 내부에서 사용될 클래스
        glut_callback::set_class(&my_box);
    
        // GLUT initialization code
        glutInit(&argc, argv);
        glClearColor(0.0, 0.0, 0.0, 0.0);
    
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
        glutCreateWindow("red 3D lighted cube");
    
        // glut main loop 이 멈추어도 나머지 코드를 실행하도록 만든다.
        glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
        glutDisplayFunc(&glut_callback::draw_callback);
        glutKeyboardFunc(&glut_callback::keyboard_callback);
        glutIdleFunc(&glut_callback::idle_callback);
        glutMainLoop();
    
        return EXIT_SUCCESS;
    }

    다운로드: AdvancedCpp.zip

    이 예제는 cube 단 하나를 렌더링하므로 콜백 함수가 그다지 어렵지 않으며, 콜백 함수로 전달할 자료의 구조도 단순한 편이다. 그러나 여러 개의 오브젝트를 그려야 한다면? 나는 그냥 ‘scene graph’ 나 Orge3D 같은 간단한 게임 엔진을 사용하기를 권장한다…. 너무 무책임한가? 🙂

    차례로 돌아가기

  • Template Callback Class

    복잡한 캐스팅 콜백 함수 단계에서 일어나는 것을 방지하기 위해 템플릿을 도입해 보았다.

    #include <iostream>
    
    // 전역변수 콜백 함수 포인터.
    // 어떤 라이브러리 어딘가에 있다고 가정한다.
    void (*g_callback)() = NULL;
    
    // callback과 상속 관계가 없는 데이터 저장 클래스
    class storage
    {
    public:
        storage()  {}
        ~storage() {}
    
        int&       val()       { return val_; }
        const int& val() const { return val_; }
    
    private:
        int val_;
    };
    
    // 정적변수만을 취급하는 기본 클래스를 선언하였다.
    template <typename T>
    class callback_base
    {
    protected:
        callback_base() {}
        ~callback_base() {}
    
    public:
        static void set_class(T* _ptr)
        {
            T** base_ptr;
    
            base_ptr    = get_base_ptr();
            (*base_ptr) = _ptr;
        }
    
        // 이중 포인터 표현을 감출 수 있다.
        // 어떤 것을 사용하는지는 사실 사용자의 취향에 따라 달라질 수 있다.
        inline static T& get_class() { return **get_base_ptr(); }
    
    protected:
        // static 변수를 함수 안에 삽입하였다.
        // 그렇지만 엄연히 cb는 존재한다.
        static T** get_base_ptr()
        {
            static T* base;
            return &base;
        }
    };
    
    class callback_class : public callback_base<storage>
    {
    // cb_base의 직접적인 생성은 금지되어 있다.
    protected:
        callback_class() {}
        ~callback_class() {}
    
    public:
        // 라이브러리가 필요로 하는 콜백 함수
        // 상위 클래스에서만 스태틱 변수를 관리하고
        // 상위 클래스를 상속받아 콜백 함수를 새롭게 정의한다.
        // storage 클래스는 사용자가 직접 만들어야 할 변수이다.
        static void callback()
        {
            // 멤버 변수를 조작할 수 있도록 클래스를 얻는다.
            // 구질구질한 포인터 참조 연산자가 사라졌다.
            storage&  real = get_class();
    
            std::cout << "member variable n: " << real.val() << std::endl;
        }
    };
    
    int main(int argc, char** argv)
    {
        // 일반적인 데이터 저장 클래스이다.
        // 복수 개를 선언하여 여러 콜백이 동시에 동작할 수 있는지 확인한다.
        storage s1, s2;
    
        s1.val() = 10;
        s2.val() = 20;
    
        // 같은 static 함수를 callback하되
        g_callback = &callback_class::callback;
    
        // 때때로 다른 데이터를 선택하도록 한다.
        // 템플릿 인자로 데이터 타입이 명시되어 가독성이 높아지는 부가적인 효과를 얻었다.
        callback_class::set_class(&s1);
        g_callback();    
    
        callback_class::set_class(&s2);
        g_callback(); 
    
        return EXIT_SUCCESS;
    }

    템플릿을 사용하여 클래스를 사용할 수 있는 콜백 형태를 만들었다.  하지만 여전히 몇몇 문제가 남아 있을 것이다. 그 중 “다양한 데이터 클래스들의 콜백 함수를 다룰 때는 그 다양한 인자를 어떻게 콜백 함수로 전달할 것인가?”라는 문제는 직감적으로 다가온다.

    일단, 내 기본적인 아이디어는 콜백 함수에서 스태틱 포인터 변수를 활용하여 데이터 관리 객체의 비정적 멤버 변수에 접근하는 방법을 제안하는 것이며, 실제로 이 아이디어는 나 혼자만의 아이디어는 아님을 밝혀 둔다. 또한 이 방법이 최선이라고는 말할 수 없다. 더 훌륭한 방법들이 존재할 것이다.

    어쨌든 C-Style의 콜백 함수가 그다지 C++에 걸맞는 구조가 아님에도 불구하고,
    이런 방법을 통해 콜백 함수에서 클래스를 사용할 수 있다는 것을 제안함에 의의를 둔다.

    참조:
    CPUBitmap Class, J. Sanders, E. Kandrot, ‘CUDA by Example’, Addison Wesley.

    차례로 돌아가기

  • Data Class and Callback Class

    스태틱 클래스 함수라도 자기 자신을 참조하는 스태틱 클래스 변수에 힘입어 자신의 비스태틱 멤버 변수 및 함수에 접근할 수 있게 되었다. 그러나 콜백 함수 내부에서 접근 제한이 불가능한 문제를 발견할 수 있었다. 이러한 문제는 데이터/콜백 클래스를 각기 완전히 분리를 하면 해결할 수 있다.

    #include <iostream>
    
    // 전역변수 콜백 함수 포인터.
    // 어떤 라이브러리 어딘가에 있다고 가정한다.
    void (*g_callback)() = NULL;
    
    // callback과 상속 관계가 없는 데이터 저장 클래스를 만든다.
    class storage
    {
    public:
        storage()  {}
        ~storage() {}
    
        int&       val()       { return val_; }
        const int& val() const { return val_; }
    
    private:
        int val_;
    };
    
    // 정적변수만을 취급하는 기본 클래스를 선언하였다.
    class callback_base
    {
    protected:
        callback_base() {}
        ~callback_base() {}
    
    public:
        static void set_class(void* _ptr)
        {
            void** base_ptr;
    
            base_ptr    = get_base_ptr();
            (*base_ptr) = _ptr;
        }
    
    protected:
        // static 변수를 함수 안에 삽입하였다.
        // 그렇지만 엄연히 cb는 존재한다.
        static void** get_base_ptr()
        {
            static void* base;
            return &base;
        }
    };
    
    // 콜백 함수만을 정의할 수 있도록 콜백 기본 클래스를 상속받는다.
    class callback_class : public callback_base
    {
    // cb_base의 직접적인 생성은 금지되어 있다.
    protected:
        callback_class() {}
        ~callback_class() {}
    
    public:
        // 라이브러리가 필요로 하는 콜백 함수
        // 상위 클래스에서만 스태틱 변수를 관리하고
        // 상위 클래스를 상속받아 콜백 함수를 새롭게 정의한다.
        // storage 클래스는 사용자가 직접 만들어야 할 변수이다.
        static void callback()
        {
            // 멤버 변수를 조작할 수 있도록 클래스를 얻는다.
            storage&  real = *(storage*)(*get_base_ptr());
    
            std::cout << "member variable n: " << real.val() << std::endl;
        }
    };
    
    int main(int argc, char** argv)
    {
        // 일반적인 데이터 저장 클래스이다.
        // 복수 개를 선언하여 여러 콜백이 동시에 동작할 수 있는지 확인한다.
        storage s1, s2;
    
        s1.val() = 10;
        s2.val() = 20;
    
        // 같은 static 함수를 callback하되
        g_callback = &callback_class::callback;
    
        // 때때로 다른 데이터를 선택하도록 한다.
        callback_class::set_class(&s1);
        g_callback();    
    
        callback_class::set_class(&s2);
        g_callback(); 
    
        return EXIT_SUCCESS;
    }

    멤버 변수로 존재하던 정적 변수를 정적 함수 내부로 집어 넣었다. 콜백 클리스와 데이터 클래스를 분리시킴으로써 콜백이 보다 구조적인 형태를 갖추었다. 실제로 콜백을 구현할 때에는 콜백의 기본 클래스를 상속받아  라이브러리가 필요한 형태의 콜백 함수를 정적 함수 형태로 구현하면 된다.

    그러나 아직 마음에 걸리는 것이 있다.  바로 콜백 부모 클래스의 ‘void *’가 그것이다. 이것이 콜백함수를 구현하는 중에 복잡한 캐스팅을 일으키게 한다. 이를 없애는 방법은 없을까? 나는 템플릿이 해결해줄 수 있을 것이라 생각한다..

    차례로 돌아가기

  • Static Variable

    일반적인 클래스로는 c-style의 콜백을 처리할 수 없다는 것을 알았고, 이는 단순한 대처로는해결하기 힘듬을 알았다. 그렇다면 어떻게 클래스를 사용하면서도, c-style을 유지할 수 있을까?

    한 가지 방법으로는 static 변수를 멤버 변수로 사용하는 방법이다. 그러나 이 방법은 그리 유용하지 못하다. 왜냐하면 static 멤버 변수는 클래스를 선언하지 않고도 사용 가능하며, 그 클래스가 모두 공유하는 변수이기 때문에, 사실상 전역 변수이나 다름이 없어지기 때문이다.

    우리는 클래스의 멤버 변수가 코드 안에서 자유롭게 선언되기를 (정확하게는 스택/힙 영역에서 메모리 확보가 이루어지기를) 원한다.  한가지 기본적인 대안은, 콜백 함수 내에서 자신이 속한 클래스의 레퍼런스를 가지고 있다가 콜백 함수에서 사용하는 것이다. 이 방법은 나름 설득력이 있어 보인다.

    #include <iostream>
    
    // 전역변수 콜백 함수 포인터.
    // 어떤 라이브러리 어딘가에 있다고 가정한다.
    void (*g_callback)(void) = NULL;
    
    // 우리는 C-Style의 함수가 아닌 class를 필요로 한다.
    class cb_class
    {
    public:
         cb_class() : n(100) {}
        ~cb_class() {}
    
        // 라이브러리는 이 함수를 필요로 한다.
        // static 키워드를 포함할 때와 그렇지 않을 때를 비교하라.
        static void callback(void)
        {
            cb_class& real = *ptr;
    
            std::cout << "Our callback function is called.n";        
    
            std::cout << "member variable n: " << real.n << std::endl;
        }
    
        static cb_class* ptr;
    
    private:
        int n;
    };
    
    cb_class* cb_class::ptr = NULL;
    
    int main(int argc, char** argv)
    {
        // 라이브러리에 우리의 콜백 함수를 등록하는 과정이라고 가정한다.
        g_callback = &cb_class::callback;
    
        // 일반적인 콜백 클래스를 선언한다.
        cb_class cb;
        cb_class::ptr = &cb;
    
        // g_callback이 우리가 만든 callback을 대신한다.
        // 현재 우리가 만든 main 함수 안에서 호출되고 있으나
        // 이 while문의 구조는 라이브러리 내부 어딘가라고 가정한다.
        int nCount = 3; // 3회 callback 함수를 호출
        while(nCount--)
        {
            g_callback();
        }
    
        return EXIT_SUCCESS;
    }

    가장 단순한 형태이지만, 이것은 콜백을 수행하는 스태틱 함수에서 멤버 변수를 사용할 수 있는 방법이 될 수 있다. 그러나 콜백함수의 인자를 넣고 참조하는 방법의 가독성은 좋지 않을 뿐더러, 콜백 함수에서 클래스의 멤버에 아무 제한 없이 접근할 수 있다는 점은 문제로 남아 있다. 이러한 문제는 콜백 클래스와 데이터 클래스를 분리함으로써 해결할 수 있다.

    차례로 돌아가기

  • Callback and Class

    C-Style의 callback 코드에 살짝 C++ 개념을 얹어 보자.

    #include <iostream>
    
    // 전역변수 콜백 함수 포인터.
    // 어떤 라이브러리 어딘가에 있다고 가정한다.
    void (*g_callback)(void) = NULL;
    
    // 우리는 C-Style의 함수가 아닌 class를 필요로 한다.
    // C++에서 class와 struct의 차이는 단지 private이 기본이냐, public이 기본이냐의 차이다.
    struct cb_class
    {
        // 라이브러리는 이 함수를 필요로 한다.
        // static 키워드를 포함할 때와 그렇지 않을 때를 비교하라.
        static void callback(void)
        {
            std::cout << "Our callback function is called.n";
        }
    };
    
    int main(int argc, char** argv)
    {
        // 라이브러리에 우리의 콜백 함수를 등록하는 과정이라고 가정한다.
        g_callback = &cb_class::callback;
    
        // g_callback이 우리가 만든 callback을 대신한다.
        // 현재 우리가 만든 main 함수 안에서 호출되고 있으나
        // 이 while문의 구조는 라이브러리 내부 어딘가라고 가정한다.
        int nCount = 3; // 3회 callback 함수를 호출
        while(nCount--)
        {
            g_callback();
        }
    
        return EXIT_SUCCESS;
    }

    static 키워드를 붙이지 않았을 경우,
    error C2440: ‘=’ : cannot convert from ‘void (__thiscall cb_class::* )(void)’ to ‘void (__cdecl *)(void)’
    에러를 내며 컴파일이 올바르게 수행되지 않는다.
    클래스의 멤버 함수는 C-Style의 콜백 함수로써 사용이 불가능하며, 굳이 사용해야 할 경우 반드시 ‘정적 멤버 함수’로 만들어야 한다. 이로써 문제점이 명확히 제시되었다.

    “우리는 어떻게 해서든 클래스의 멤버 변수를 사용하고 싶다!”

    차례로 돌아가기

  • C-Style Callback

    먼저 C-Style Callback이 무엇인지를 설명하고자 한다.
    보다 기술적인 설명을 하는 것 보다 다음 코드를 읽으면서 이야기를 진행하자.

    #include <stdio.h>
    #include <stdlib.h>
    
    // 전역변수 콜백 함수 포인터.
    // 어떤 라이브러리 어딘가에 있다고 가정한다.
    void (*g_callback)(void) = NULL;
    
    // 우리가 직접 만들어야 하는 콜백 함수
    // 라이브러리는 이 함수를 필요로 한다.
    void callback(void)
    {
        printf("Our callback function is called.n");
    }
    
    int main(int argc, char** argv)
    {
        int nCount = 3; // 3회 callback 함수를 호출
    
        // 라이브러리에 우리의 콜백 함수를 등록하는 과정이라고 가정한다.
        g_callback = callback;
    
        // g_callback이 우리가 만든 callback을 대신한다.
        // 현재 우리가 만든 main 함수 안에서 호출되고 있으나
        // 이 while문의 구조는 라이브러리 내부 어딘가라고 가정한다.
        while(nCount--)
        {
            g_callback();
        }
    
        return EXIT_SUCCESS;
    }

    6행에 지정한 전역 변수는 우리가 의도한 것이 아닌 어떤 라이브러리 안에 포함된 가상의 함수 포인터를 의미한다. 이 프로그램의 핵심은 20번째 줄에서 우리가 만든 함수가 전역 변수에 대입되고, 27번째 줄에서 비로소 콜백이 호출된다는 것이다.

    결과는 기본적인 C언어 함수 포인터의 예제 수준을 벗어나지 않으나, 어떤 C-Style의 라이브러리를 쓰더라도 위 코드와 거의 유사한 시나리오로 진행될 것이다. 우리는 여기서부터 시작해 원하는 결과까지 도달할 것이다.

    차례로 돌아가기

  • CUDA를 위한 Visual Studio Template 변경

    Visual Studio 2010 Templates Window
    "Add.." 메뉴를 선택하면 다음과 같이 미리 정해진 파일을 프로젝트에 삽입할 수 있다.

    위 그림처럼 CUDA의 ‘.cu’, ‘.cuh’ 확장자를 가진 파일도 비주얼 스튜디오의 “Add New Item” 다이얼로그 박스를 통해 추가시키는 방법을 기록한다.

    “Add New Item” 메뉴를 클릭하면 나오는 메뉴 설정은 (C++의 경우) 다음과 같이 세팅한다.

    1. “C:Program Files (x86)Microsoft Visual Studio 10.0VCvcprojectitems” 디렉토리로 가서
    2. newc++file.cpp‘ 파일과 ‘hfile.h‘ 두 파일을 찾아 복사한 후 각각 ‘NewCUDAFile.cu‘, ‘CUDAHFile.cuh‘로 변경한다.변경한 확장자를 가진 파일을 열 때마다 사용할 수 있도록 각 파일에 임의의 코드를 적어 넣을 수도 있다. 관리자 권한이 필요하다.
    3. VCProjectItems.vsdir‘ 디렉토리를 열어 다음 두 줄을 추가한다.
      NewCUDAFile.cu|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|CUDA Source File (.cu)|11|Creates a file contaning CUDA C source code|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9031|4096|CUDA_C
      CUDAHFile.cuh|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|CUDA Header File (.cuh)|16|Create a CUDA C header file|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9030|4096|CUDA_HEADER
    4. 현재 디렉토리 아래의 ‘Code‘ 디렉토리의 ‘code.vsdir‘를 열어 다음 두 줄을 추가한다.
      ..NewCUDAFile.cu|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|CUDA Source File (.cu)|17|Creates a file contaning CUDA C source code|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9031|4096|CUDA_C
      ..CUDAHFile.cuh|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|CUDA Header File (.cuh)|18|Create a CUDA C header file|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|9030|4096|CUDA_HEADER
    5. Visual Stuio 2010을 다시 실행한 후, “Add New Item”을 클릭해서 나오는 다이얼로그(Visual C++ 항목 및 Code 항목)에 “CUDA Source File’과 “CUDA Header File” 메뉴가 추가된 것을 확인할 수 있다.

    참고 자료: Template Directory Description (.Vsdir) Files

     

    덧)

    • clsid 항목에 대한 이해가 부족해 cu, cuh 파일에 대한 아이콘까지는 변경하기 어려웠다.
    • 또한 #ResId는 MFC의 리소스아이디와 같은 개념으로 생각하지만, 이 실제 문자열은 어디에 존재하는지 현재로서는 알 길이 없다.
    • cu, cuh의 위치를 조정하기 위해서는 SortPriority 항목을 변경하면 된다.
    • 약간 불충분하지만 이 정도로도 CUDA 파일 추가할 때 일일이 확장자를 쳐 주지 않아도 되어 편리하다.

     

  • CUDA 초기 세팅 (Ver 4.1 기준)

    [패키지 설치]

    보통 CUDA를 설치하면 아래 세 가지 패키지를 설치하게 된다.

    • CUDA Developer Driver: CUDA 개발을 위한 드라이버.
    • CUDA Toolkit: nvcc, 디버거, 프로파일러 등이 있는 CUDA 개발을 위한 패키지.
    • GPU Computing SDK: 샘플 코드들

    패키지를 설치하면 다음과 같은 전역 환경 변수가 정의된다.

    • CUDA_BIN_PATH
    • CUDA_INC_PATH
    • CUDA_LIB_PATH
    • CUDA_PATH
    • CUDA_PATH_V4_1

    그리고 다음 환경 변수가 업데이트된다.

    • Path

     

    [Visual Studio 2010 세팅]

    설치 OS 는 Windows 7 64bit를 대상으로 하고, CUDA 프로그래밍 세팅은 32bit 환경으로 한다.

    CUDA Extension 세팅

    1. 프로젝트에 cu, cuh 파일 인식: Tools – Options – VC++ Project Settings – Extensions To Include에 “;.cu;.cuh” 추가
    2. Tools – Options – Text Editor – File Extension에 cu, cuh extension 추가. 이 때 “Editor”는 “Microsoft Visual C++”를 선택한다.

     

    Syntax Highlighting

    1. CUDA SDK를 설치한 디렉토리의 .Cdocsyntax_highlightingvisual_studio_8usertype.dat 를 연다.
    2. C:Program FilesMicrosoft Visual Studio 10.0Common7IDEusertype.dat(관리자 권한 필요)를 연다.
    3. “…visual_studio_8usertype.dat”의 설정값을 “…IDEusertype.dat” 항목에서 복사해 넣고 저장한다.

     

    [추가: Visual Assist X 설정]

    1. 비주얼 스튜디오를 끄고 레지스트리 편집기를 켠다.
    2. 64비트는 HKEY_LOCAL_MACHINESOFTWAREWow6432NodeMicrosoftVisualStudio10.0LanguagesFile Extensions.cpp
      32비트는 HKEY_LOCAL_MACHINESOFTWAREMicrosoftVisualStudio10.0LanguagesFile Extensions.cpp
      을 복사하여 .cu 항목을 만든다.
    3. 위 항목과 마찬가지로 .h 항목을 복사하여 .cuh 항목을 만든다.
    4. HKEY_CURRENT_USERSoftwareWhole TomatoVisual Assist XVANet10ExtHeader에 헤더인 “.cuh;” 를 넣어 준다.
      HKEY_CURRENT_USERSoftwareWhole TomatoVisual Assist XVANet10ExtSource에 “.cu;”를 넣어 준다.
    5. Visual Assist X 옵션의 “Performance” 에서 “Rebuild”를 눌러 주고 IDE를 다시 시작한다.

     

    출처:

     

  • Visual Studio의 CUDA Project 설정하기

    초기 세팅에 관한 포스트는 CUDA 초기 세팅 (Ver 4.1 기준)에서 다루었다. 이번에는 Visual Studio 10의 설정에서 CUDA를 설정, 컴파일하는 과정을 기록한다.

    [Visual Studio Project 생성 예제]

    CUDA 4.1이 정상적으로 설치되었다고 가정하고, 프로젝트를 생성한다.

    1. 프로젝트는 Win32 Console Application (Visual C++)로 하고 ‘Empty project’에서 시작한다.
    2. 파일을 하나 작성한다.
      #include <iostream>
      #include "cuda.h"
      #include "cuda_runtime.h"
      #include "device_launch_parameters.h"
      
      __global__ void kernel(void)
      {
      }
      
      __global__ void help(void)
      {   
      }
      
      int main(void)
      {
          kernel<<<1, 1>>>();
          printf("Hello, World!n");
          return 0;
      }
    3. Solution Explorer에서 project를 선택하고 ‘Build Customizations’를 클릭한다. 정상적으로 CUDA가 설치되어 있다면 CUDA 4.1 타겟이 윈도우에 보일 것이다. 이것에 체크한다.
      만일 설치되지 않았거나 지워졌다면, CUDA Toolkit가 설치된 디렉토리의 ‘extrasvisual_studio_integrationMSBuildExtensions’ 에 있는모든 파일을 ‘C:Program Files (x86)MSBuildMicrosoft.Cppv4.0BuildCustomizations’ 에 복사한다.
    4. 세팅이 올바르게 되어 있으면 다음처럼 .cu 파일 안에서도 .cpp 파일과 같은 화면으로 보일 것이다.

      참고) CUDA 관련 함수들이 올바로 인텔리센스에 나오게 하려면 CUDA의 헤더 파일들을 명시적으로 기입해주어야 한다.

    5. 컴파일을 수행한다. 컴파일은 문제 없이 수행되지만, 링크 에러가 발생할 것이다. 나는 property sheet 수정을 이용해 해결할 것이다.

     

    [Visual Studio project default property sheet 수정]

    CUDA 4.1을 설치한 후에는 기본적인 perperty sheet인 “Microsoft.Cpp.Win32.user” 파일이 살짝 변경된다. 하지만 빌드하기 편하게 몇가지 것들을 더 수정한다.
    이 작업은 한 번만 수행하면 된다.

    cudart.lib 설정

    1. View – Property Manager (메뉴 마지막에서 두 번째) 를 선택한다. Property Manager 도킹 창이 나타난다.
    2. Microsoft.Cpp.Win32.user property page를 연다.
    3. Linker – Input – Addtional Dependencies에 cudart.lib 파일을 추가한다. 기존 항목은 *절대* 지워서는 안 된다.
    4. 변경 전: kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;
      advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;
      odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
    5. 변경 후: kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;
      advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;
      odbc32.lib;odbccp32.lib;cudart.lib;%(AdditionalDependencies)
      (사실 아예 새로운 property를 추가하는 것을 더 권장하지만, 주의를 충분히 기울일 경우 본 방법이 훨씬 편리하긴 하다.)

     

    [Troubleshooting]

    • .cu 파일을 작성하였으나 nvcc 컴파일러가 동작하지 않는다.
      •  ‘Build Customizations’를 선택해 CUDA 4.1 을 선택한다. Projec properti pages를 열어 ‘CUDA C/C++’ 항목이 추가되었는지 확인한다. 추가되지 않았다면 cu 파일에 대한 custom build rule이 제대로 적용되지 않았기 때문이다. cu 파일의 property를 열어 General – Item Type이 ‘CUDA C/C++’ 로 설정되어 있는지를 확인하자.
    • #include … 로 추가한 CUDA 관련 header 파일의 경로를 찾을 수 없다고 에러가 나온다. (#include 를 선언한 줄에 커서를 가져가 마우스 오른쪽 클릭 후 나오는 context menu에서 “Open Document < … > ..” 를 선택했을 때 에러 메시지가 나오는 경우.
      • 이는 정상적인 현상이다. ‘.cu’ 파일은 일반적인 C/C++ 파일 확장자가 아니다. 그러므로 ‘Additional Include Directories’에서 설정한 값이 적용되지 않는다. 정 context menu에서 header를 열고 싶다면 “Microsoft.Cpp.Win32.user” property sheet의 ‘Include Directories’에 ‘$(CudaToolkitIncludeDir)’를 추가하라.

     

  • CUDA by Example 소스 코드

    NVIDIA 공식 홈페이지에 링크가 잘려 있어서 올려둔다. 본 도서의 공식 홈페이지 링크는 여기이다.

    다운로드: CUDA by Example Source Code

  • Simple Subtitle Renamer GUI

    Simple Subtitle Renamer GUI

    예전에 만들었던 smiRenamer는 지금까지 쏠쏠하게 잘 쓰고 있다.
    이번에 약간의 기능을 더 추가하여 새롭게 다시 만들어 보았다.
    이번에 이름은 SubRenamer라고 이름지었다.

    이전과 마찬가지로 어떤 영상 파일과 자막 파일이 있는 경우,
    두 파일의 이름을 동일하게 맞추어 주는 프로그램이다.

    단순히 파일 이름의 변경만을 원하는 경우, 파일 이름만을 전문적으로 바꾸어주는 툴을 사용할 수도 있지만, 이것은 동영상-자막 파일의 이름을 맞추는데 특화되어 있다는 것이 특징이랄가.

    이전에 비해 동영상/자막 타입을 사용자가 결정할 수 있고, 하위검색에 대한 기능이 보강되었다. 그리고 지정한 확장자를 가진 파일에 대해 정규식 검색을 할 수 있어 더욱 원하는 파일만을 볼 수 있도록 하였다.

    SubRenamerGUI ]

  • DOXYGEN_DOT_EXECUTABLE

    doxygen의 시각화 도구 Graphviz를 말하는 것임.

    http://www.graphviz.org/Download_windows.php 에서 패키지 다운로드

     

  • Sphinx 에 관한 설정

    PCL 컴파일 시 CMAKE의 항목 중

    SHPINX-EXECUTABLE 항목을 찾을 수 있다. 이는 python을 이용한 문서 제작을 위한 라이브러리이다. (홈페이지)

    설치는 다음과 같이 수행한다.

    1. http://pypi.python.org/pypi/Sphinx#downloads 에서 파이썬 버전에 맞는 egg 파일을 다운로드 받는다.
    2. http://pypi.python.org/pypi/setuptools 에서 setuptools (ez_setup.py)를 받는다.
      그리고 이것을 콘솔에서 실행한다.
      >> python ez_setup.py
    3. easy_install.exe 파일이 파이썬 디렉토리의 Scripts 하위 디렉토리에 생성된다. 패스 걸어주고,
    4. egg 디렉토리로 가서 다음과 같이 실행하면 끝
      >> easy_install  Sphinx-1.1.2-py2.7.egg

    설치 후, CMake가 스크립트에서 Sphinx 위치를 알아낸다.

     

     

     

  • 학교 배경 달력

    필받아서 만들어버린 달력

    국민대학교 11월 1일
    학교 촬영

     

     

  • Branch and Bound algorithm

    PFH (Persistent Feature Histogram) 을 설명한 논문 “Aligning Point Cloud Views using Persistent Feature Histograms“에 의하면 feature의 alignment를 맟추기 위해 “Robust Global Registration”을 인용하였다.
    Robust Global Registration에 따르면 alignment는 ‘branch and bound’ 알고리즘을 사용하는데, 이는 텍스트 북이나 다음 링크에서 참고할 수 있다:

    알고리즘의 개략적인 내용은 값을 가질 수 있는 가능성을 tree 형태로 생각한다. BST로 각 트리의 노드를 방문할 때 어떤 경계값을 계산한다.  경계값이 현재 최선의 값보다 낫다면 더욱 나아질 가능성이 있다고 판단하여 그 노드의 자식 노드를 방문 대상에 포함시키며, 그렇지 않을 경우는 제외한다.

     

  • 보호된 글: Thunder-Light Rain

    이 콘텐츠는 비밀번호로 보호되어 있습니다. 이 콘텐츠를 보려면 아래에 비밀번호를 입력해주세요: