300x250
반응형

 

 

 

프로젝트 문자집합이 Unicode 인경우 ( 기본 )

CString str = _T("Hello, world!");

// CString을 Unicode 문자열로 변환
CW2A pszConvertedAnsiString(str);
// CString의 내부 버퍼에 대한 포인터 가져오기
const char* pszConvertedString = pszConvertedAnsiString;

위의 예제에서는 CString 객체인 str을 Unicode 문자열로 변환하기 위해 CW2A 클래스를 사용했습니다. CW2A 클래스는 CString을 char 배열로 변환해주는 역할을 합니다. 그리고 pszConvertedAnsiString 변수를 통해 변환된 문자열을 얻을 수 있습니다. 이후 pszConvertedString 변수에 변환된 문자열의 포인터를 저장하였습니다.

 

 

 

프로젝트 문자집합이 멀티바이트 인경우

CString str = _T("Hello, world!");

// CString을 multibyte 문자열로 변환
CT2CA pszConvertedAnsiString(str);
// CString의 내부 버퍼에 대한 포인터 가져오기
const char* pszConvertedString = pszConvertedAnsiString;

위의 예제에서는 CString 객체인 str을 multibyte 문자열로 변환하기 위해 CT2CA 클래스를 사용했습니다. CT2CA 클래스는 CString을 char 배열로 변환해주는 역할을 합니다. 그리고 pszConvertedAnsiString 변수를 통해 변환된 문자열을 얻을 수 있습니다. 이후 pszConvertedString 변수에 변환된 문자열의 포인터를 저장하였습니다.

 

 

 

300x250
반응형
300x250
반응형

 

솔루션 탐색기 -> 하단 속성관리자에 들어가면 아래와 같은 화면이 뜹니다.

원하는 프로젝트 선택 후 -> 32 / 64비트, debug / release 선택 후

우클릭해서 속성으로 들어갑니다.

 

 

 

공용 속성에서 사용자 메크로 선택후 메크로 추가

기존에 메크로가 TargetName 이 있습니다.

저는 Debug모드로 컴파일시 파일명에 D를 추가하기 위해 TargetNameD 라는 메크로를 만들었습니다.

 

 

프로젝트 우클릭해서 속성창으로 가면

해당 debug / release, x64, x86 에 맞는걸 선택후

링커 -> 출력파일로 가서

아까 추하해둔 사용자 메크로 변수 TargetNameD 를 입력하였습니다.

컴파일이 아래와 같이 뒤에 "D" 가 붙을수 있도록 하였습니다.

 

 

 

실행파일 설정은 여기까지 만 하면되고

만약 DLL을 만든다고 하면 Lib 파일도 D를 붙여야 하기때문에 아래설정을 하나더 해줘야 합니다.

 

링커 -> 고급 -> 가져오기 라이브러리

TargetNameD 라는 설정 변경

 

300x250
반응형
300x250
반응형

 

쉐이더 프로그램을 종료하기 위해서는  NULL 또는 0으로 값을 넣어서 종료시켜줘야 합니다.

glUseProgram(NULL); 또는 glUseProgram(0);

 

 

아래 여러 예를 들어볼께요.

예제1 ) 단순 프로그램 종료 예시 입니다.

만약 glUseProgramObjectARB을 사용했다면 똑같이 glUseProgramObjectARB로 사용하면 됩니다.

programID = LoadShaders("VertexShader.txt", "FragmentShader.txt");
glUseProgram(programID);
...
...
...
glUseProgram(NULL);

 

예제2) 여러 버퍼를 바인딩한 경우의 예시

프로그램 사용과 VAO 바인딩, 각종 버퍼를 바인딩 한 경우에는 전부 해제해줘야 한다.

programID = LoadShaders("VertexShader.txt", "FragmentShader.txt");
glUseProgram(programID);

glGenVertexArrays(1, &VAO[0]);  // 1.할당 (앞에 인자는 1개 의미)
glBindVertexArray(VAO[0]);

glGenBuffers(1, &VBO[0]);  // 1.할당 (앞에 인자는 1개 의미)
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);

glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

...
...
...
glUseProgram(NULL);
glBindVertexArray(NULL);
glBindBuffer(GL_ARRAY_BUFFER, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);

 

 

300x250
반응형
300x250
반응형

프로그램 및 코드 다운로드

2. Example_OpenGL_EBO_VAO_VBO.zip
7.74MB

주요 코드는 아래와 같습니다.

#pragma once
#include "GlRender.h"

class RenderEBO_VAO_VBO : public GlRender
{
public:
    RenderEBO_VAO_VBO();
    ~RenderEBO_VAO_VBO();
    
private:
    void GlInit() override;
    void GlDraw() override;

    float vertices[4] = {
        0,10,
        200, 110
    };
    float vertices2[4] = {
        0,20,
        200, 120
    };


    GLuint VAO;
    GLuint VAO2;

    GLuint VBO;
    GLuint VBO2;


    GLuint EBO;
    GLuint VAO3;
    GLuint VBO3;


    float vertices3[12] = {
        50.5f,  50.5f, 0.0f,  // 우측 상단
        50.5f, -50.5f, 0.0f,  // 우측 하단
        -50.5f, -50.5f, 0.0f,  // 좌측 하단
        -50.5f,  50.5f, 0.0f   // 좌측 상단
    };
    unsigned int indices[6] = {  // 0부터 시작한다는 것을 명심하세요!
        0, 1, 3,   // 첫 번째 삼각형
        1, 2, 3    // 두 번째 삼각형
    };

};

 

아래 코드에서는 VAO + VBO를 2개 만들어서 2개의 라인을 그립니다.

그리고 EBO + VAO + VBO를 사용하여 정점 좌표를 인덱싱하여 순서를 변경 합니다.

위에 헤더의 indices를 주목해 주세요.

0~4 사이의 순서를 변경하면 LINE_STRIP 그리는 위치가 바뀌게 됩니다.

void RenderEBO_VAO_VBO::GlInit()
{    
    /***************************************************************************************
    * VAO + VBO 1번째
    **************************************************************************************/
    // VAO 생성 및 바인딩
    glGenVertexArrays(1, &VAO);  // 1.할당 (앞에 인자는 1개 의미)
    glBindVertexArray(VAO);

    // VBO
    // 1. Gen(할당) -> 2. Bind(바인딩) -> 3. Data(입력) -> 4. Link 순서로 사용
    glGenBuffers(1, &VBO);  // 1.할당 (앞에 인자는 1개 의미)
    glBindBuffer(GL_ARRAY_BUFFER, VBO); // 2. GL_ARRAY_BUFFER 형식 바인딩 (이 버퍼 말고도 종류가 많음)
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW); // 3.데이터 복사 및 크기 설정
    ///GL_STATIC_DRAW: 데이터가 거의 변하지 않습니다.
    ///GL_DYNAMIC_DRAW: 데이터가 자주 변경됩니다.
    ///GL_STREAM_DRAW: 데이터가 그려질때마다 변경됩니다.

    // 4. Link Vertex Attribute
    int location = 0;
    glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GL_FLOAT), (void*)0);
    glEnableVertexAttribArray(location);



    /***************************************************************************************
    * VAO + VBO 2번째
    **************************************************************************************/
    // VAO 생성 및 바인딩
    glGenVertexArrays(1, &VAO2); // 1.할당 (앞에 인자는 1개 의미)
    glBindVertexArray(VAO2); // VAO를 OpenGL context에 연결(bind)

    // VBO
    // 1. Gen(할당) -> 2. Bind(바인딩) -> 3. Data(입력) -> 4. Link 순서로 사용
    glGenBuffers(1, &VBO2);   // 1.할당 (앞에 인자는 1개 의미)
    glBindBuffer(GL_ARRAY_BUFFER, VBO2); // 2. GL_ARRAY_BUFFER 형식 바인딩 (이 버퍼 말고도 종류가 많음)
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STREAM_DRAW); // 3.데이터 복사 및 크기 설정
    ///GL_STATIC_DRAW: 데이터가 거의 변하지 않습니다.
    ///GL_DYNAMIC_DRAW: 데이터가 자주 변경됩니다.
    ///GL_STREAM_DRAW: 데이터가 그려질때마다 변경됩니다.

    // 4. Link Vertex Attribute
    glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GL_FLOAT), (void*)0);
    glEnableVertexAttribArray(location);



    /***************************************************************************************
     * EVO + VAO + VBO
     **************************************************************************************/
    // VAO 생성 및 바인딩
    glGenVertexArrays(1, &VAO3);  // 1.할당 (앞에 인자는 1개 의미)
    glBindVertexArray(VAO3);  // VAO를 OpenGL context에 연결(bind)

    // VBO
    // 1. Gen(할당) -> 2. Bind(바인딩) -> 3. Data(입력) -> 4. Link 순서로 사용
    glGenBuffers(1, &VBO3);   // 1.할당 (앞에 인자는 1개 의미)
    glBindBuffer(GL_ARRAY_BUFFER, VBO3);  // 2. GL_ARRAY_BUFFER 형식 바인딩 (이 버퍼 말고도 종류가 많음)
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices3), vertices3, GL_STREAM_DRAW); // 3.데이터 복사 및 크기 설정

    // OpenGL이 사용하기 위해 인덱스 리스트를 element 버퍼에 복사
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STREAM_DRAW);
    ///GL_STATIC_DRAW: 데이터가 거의 변하지 않습니다.
    ///GL_DYNAMIC_DRAW: 데이터가 자주 변경됩니다.
    ///GL_STREAM_DRAW: 데이터가 그려질때마다 변경됩니다.

    // Link Vertex Attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
}

 

void RenderEBO_VAO_VBO::GlDraw()
{
    glViewport(0, 0, gl_window_width, gl_window_height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho((double)-gl_window_width / 2, (double)gl_window_width / 2,
        (double)-gl_window_height / 2, (double)gl_window_height / 2,
        1, -1);
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0, 0, 0, 0);


    glBindVertexArray(VAO);	// 한 줄로 끝!
    glColor4f(0, 1, 0, 1);
    glDrawArrays(GL_LINES, 0, 2);


    glBindVertexArray(VAO2);	// 한 줄로 끝!
    glColor4f(0, 0, 1, 1);
    glDrawArrays(GL_LINES, 0, 2);


    glBindVertexArray(VAO3);	// 한 줄로 끝!
    glColor4f(0, 0, 1, 1);
    glDrawElements(GL_LINE_STRIP, 6, GL_UNSIGNED_INT, 0); // EBO 사용 시 glDrawElements로 출력
}
300x250
반응형
300x250
반응형

프로그램 및 코드 다운로드

1. Example_OpenGL_VBO.zip
7.73MB

 

주요 코드는 아래와 같습니다.

 

Header

class RenderVBO : public GlRender
{
public:
    RenderVBO();
    ~RenderVBO();

    GLuint VBO;

    float vertices[8] = {
        0,10,
        200, 110,
        -0,-10,
        -200,-110
    };


private:
    void GlInit() override;
    void GlDraw() override;
};

 

 

CPP

void RenderVBO::GlInit()
{
    // 1. Gen(할당) -> 2. Bind(바인딩) -> 3. Data(입력) -> 4. Link 순서로 사용

    glGenBuffers(1, &VBO); // 1.할당
    glBindBuffer(GL_ARRAY_BUFFER, VBO); // 2. GL_ARRAY_BUFFER 형식 바인딩 (이 버퍼 말고도 종류가 많음)
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) /* Byte 크기*/ , &vertices[0], GL_STREAM_DRAW); // 3.데이터 복사 및 크기 설정
    ///GL_STATIC_DRAW: 데이터가 거의 변하지 않습니다.
    ///GL_DYNAMIC_DRAW: 데이터가 자주 변경됩니다.
    ///GL_STREAM_DRAW: 데이터가 그려질때마다 변경됩니다.

    // 4. Link Vertex Attribute
    int location = 0;

    // 파라미터 : location, 크기, 데이터 형태(float 등), Normalize 여부, 한점 BYTE 크기 (0이면 자동 계산), 시작 인덱스
    glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GL_FLOAT), (void*)0);
    glEnableVertexAttribArray(0);

}

VBO를 사용하기 위해서는 아래순서로 사용합니다. 꼭 기억해두세요.

1. Gen(할당) -> 2. Bind(바인딩) -> 3. Data(입력) -> 4. Link 순서로 사용

 

 

void RenderVBO::GlDraw()
{
    glViewport(0, 0, gl_window_width, gl_window_height);
    glLoadIdentity();

    glOrtho((double)-gl_window_width / 2, (double)gl_window_width / 2,
        (double)-gl_window_height / 2, (double)gl_window_height / 2,
        1, -1);
    

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0, 0, 0, 0);


    glColor4f(0, 1, 0, 1);

    // 중요! 단독으로 VBO만 사용시 VBO버퍼에 마지막으로 입력된 데이터가 출력됨
    // 만약 여러 데이터를 입력하려면 VAO를 같이 사용해야 함(다음 예제 참조)
    glDrawArrays(GL_LINES, 0, 2); // glBegin(GL_LINES); 처럼 쓰면됨 GL_POINTS 등등
    
}

glDrawArrays로 버퍼에 저장된 데이터를 출력하였습니다.

 

300x250
반응형
300x250
반응형

 

 

 

 

 

이번 내용은 OpenGL을 윈도우 창과 연동하는 방법을 작성하였습니다.

 

주 내용은 간단합니다.

예제 파일에 있는 GlRender.cpp, GlRender.h 파일을 사용해서 

GlRender클래스는 자체 OpenGLCreate 관련 함수와, 쓰레드 생성 함수들이 있습니다.

나중에 GlStart()를 호출하게되면 MFC 화면에 영상이 출력됩니다.

 

RenderTest라는 클래스를 만들었습니다.

 

 

RenderTest.h

#pragma once
#include "GlRender.h"

class RenderTest : public GlRender
{
public:
    RenderTest();
    ~RenderTest();
    
private:
    void GlInit() override;
    void GlDraw() override;
};

헤더는 GlRender를 상속받습니다.

GlRender 클래스에 가상함수로 호출되기 때문에 GlInit(), GlDraw() 함수는 오버라이드! 

 

RenderTest.cpp

#include "stdafx.h"
#include "RenderTest.h"


RenderTest::RenderTest(){}

RenderTest::~RenderTest(){}

void RenderTest::GlInit(){}

void RenderTest::GlDraw()
{
    glViewport(0, 0, gl_window_width, gl_window_height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho((double)-gl_window_width / 2, (double)gl_window_width / 2,
        (double)-gl_window_height / 2, (double)gl_window_height / 2,
        1, -1);


    glMatrixMode(GL_MODELVIEW);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0, 0, 0, 0);


    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glPushMatrix();
    {
        glBegin(GL_LINES);

        glColor4f(0, 1, 0, 1);
        glVertex2d(0, 0);
        glVertex2d(200, 100);

        glEnd();
    }
    glPopMatrix();
    glDisable(GL_BLEND);



    glMatrixMode(GL_MODELVIEW);
    glMatrixMode(GL_PROJECTION);

}

 

RenderTest의 GlDraw() 함수 내용을 보면

중요한 내용은 아니지만 대략적으로 설명을 해보겠습니다.

 

1. glViewport를 사용하여 그릴 화면 영역을 잡고

2. 공간 메트릭스 행렬 초기화

3. glOrtho를 사용하여 화면 Viewport 영역 좌표계를 설정 했습니다.

4. GL_BLEND를 사용하여 투명도 적용

 

GlBegin ~ GlEnd() 내용에 색상을 정하고, 점2개로 직선을 그리는 OpenGL 코드를 작성하였습니다.

 

 

이제 MFC 화면에 연동을 해볼께요

 

0. stdafx.h에 OpenGL 환경설정 추가

#pragma comment ( lib, "OpenGL32.lib" )

#ifdef _WIN32
#include "OpenGL_lib/core/x86/glew.h"
#include "OpenGL_lib/core/x86/wglew.h"
#endif

#ifdef _WIN64
#include "OpenGL_lib/core/x64/glew.h"
#include "OpenGL_lib/core/x64/wglew.h"
#endif

 

1. 먼저 출력할 Dialog 클래스 헤더에 객체 선언

    RenderTest m_render_test;

 

2.  OnInitDialog() 함수에

m_render_test.Create(this);
m_render_test.GlStart();

 

3. OnSize() 함수에

m_render_test.GlResize(cx, cy);

 

4. OnClose() 함수에

m_render_test.GlClose();

 

 

프로그램을 실행한 결과!

 

예시 코드는 아래에서 받을 수 있습니다.

1. Example_OpenGL_MFC.zip
8.23MB

VisualStudio 2012에서 작성되었습니다.

300x250
반응형
300x250
반응형

 

이번 예제는 현재 위치에 파일이 있는지 확인하는 코드 입니다.

CString full_path = GetExecutedPath() + _T("test/file.tmp");

if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(full_path) && GetLastError() == ERROR_FILE_NOT_FOUND)
{
	AfxMessageBox(_T("파일 X"));
}
else
{
	AfxMessageBox(_T("파일 O"));        
}

GetExcutedPath() 함수는 실행파일이 있는 위치를 리턴해 줍니다.

저걸 사용안하면 프로젝트 소스가 있는 위치에서 파일을 확인하기 때문에 ㅋ

아래 함수를 그대로 복사해서 붙여넣기 하시면 됩니다.

CString GetExecutedPath()
{
    //실행파일 경로 구하는 함수
    CString strResult;
    CString strPath;

    if (GetModuleFileName(nullptr, strPath.GetBuffer(_MAX_PATH + 1), MAX_PATH) != FALSE)
    {
        strPath.ReleaseBuffer();

        strResult = strPath.Left(strPath.ReverseFind('\\') + 1);
    }

    return strResult;
}

 

 

간단하쥬 ㅋ

300x250
반응형
300x250
반응형

 


아래 코드는 파일이름 변경 예제 입니다. 아래 2가지 방법중 하나를 사용하시면 됩니다.

아래 예제는 file.tmp 라는 파일을 file.xtf 로 확장자 / 이름 변경 하는 코드 입니다.

 

1. C 코드를 사용한 변환

CString full_path_tmp = GetExecutedPath() + _T("test/file.tmp");
CString full_path_xtf = full_path_tmp;        
full_path_xtf.Replace(_T(".tmp"), _T(".xtf"));


CStringA a_full_path_tmp = (CStringA)full_path_tmp;
CStringA a_full_path_xtf = (CStringA)full_path_xtf;

const char* char_path = a_full_path_tmp.GetBuffer();
const char* char_path_changed = a_full_path_xtf.GetBuffer();

rename(char_path, char_path_changed);

C 코드인 rename을 사용합니다.

해당 파라미터는 const char*를 인자로 사용하기 때문에 변환해서 넣어야 합니다.

장점은 오류 예외창이 안뜹니다.

 

 

2. MFC 코드는 사용한 변환

CString full_path_tmp = GetExecutedPath() + _T("test/file.tmp");
CString full_path_xtf = full_path_tmp;        
full_path_xtf.Replace(_T(".tmp"), _T(".xtf"));

CFile::Rename(full_path_tmp, full_path_xtf);

MFC 함수인 CFile::Rename 함수를 사용합니다.

해당 파라미터는 CString을 그대로 사용하시면 됩니다.

단점은 파일이 없을경우 오류 메시지창이 뜹니다.

 

 

간단하쥬 ㅋ

300x250
반응형

+ Recent posts