Создаем новое OpenGL ES2 приложение на C++ в Windows | Visual Studio, Desktop application
последнее обновление: 30 декабря 2024
Скачать пример на OpenGL ES2
ProjectWindowsC++.zip ...
размер: 3 мегабайта
На заметку! OpenGL ES2 используется на Android и очень удобно сначала писать в Windows и потом программу писать на Android.
Шаг 1. Открываем Visual Studio
Шаг 2. Давайте создадим новое десктопное приложение на C++
Выбираем: Console App
Создался вот такой проект:
Запустим программу:
Увидим результат:
Шаг 3. Скачаем библиотеку OpenGL ES2 как zip
Внутри opengl_es_windows.zip вот такие файлы:
Шаг 4. Добавим файлы OpenGL ES2 в C++ проект
Мой C++ проект находится в папке:
D:\ProjectWindowsC++
Скопируем файлы из
opengl_es_windows.zip внутрь
C++ проекта вот так:
D:\ProjectWindowsC++
opengl_es_windows
libEGL.dll
libEGL.lib
libGLESv2.dll
libGLESv2.lib
include
EGL
egl.h
eglplatform.h
GLES2
gl2.h
gl2platform.h
KHR
khrplatform.h
Нажмем правой клавишей мыши в
Visual Studio и добавим
dll, lib файлы в проект:
увидим добавленные файлы:
Нажмем правой клавишей мыши на libEGL.dll и нажмем на Properties
Поставим Copy file чтобы при сборке dll копировалась:
Поставим также Copy file для libGLESv2.dll .
Нажмем правой клавишей мыши на Properties :
Добавим:
./opengl_es_windows/include/;
Шаг 5. Добавим новые файлы my_game.cpp, my_game.h в Visual Studio проект
Создадим новые файлы тут:
D:\ProjectWindowsC++\
my_game.cpp
my_game.h
C++
Файл my_game.cpp
#include "my_game.h"
#include <EGL/eglplatform.h>
#include "opengl_es_windows/include/EGL/egl.h"
MyGame::MyGame()
{
m_Width = 0;
m_Height = 0;
}
void MyGame::OnActiveFocus()
{
}
void MyGame::OnLostFocus()
{
}
bool MyGame::OnHandleTouch()
{
return false; // event not handled
}
void MyGame::OnNextTick()
{
}
// open GL
void MyGame::DrawGraphic_OpenGL()
{
if (m_Display == EGL_NO_DISPLAY || m_Surface == EGL_NO_SURFACE || m_Context == EGL_NO_CONTEXT)
return;
// green color
glClearColor(0.72f, 0.87f, 0.55f, 1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(m_Display, m_Surface);
}
void MyGame::CreateSurfaceFromWindow_OpenGL(HWND window)
{
const EGLint attribs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE};
EGLint format;
EGLint numConfigs;
eglChooseConfig(m_Display, attribs, &m_configOpenGL, 1, &numConfigs);
eglGetConfigAttrib(m_Display, m_configOpenGL, EGL_NATIVE_VISUAL_ID, &format);
m_Surface = eglCreateWindowSurface(m_Display, m_configOpenGL, window, NULL);
}
void MyGame::KillSurface_OpenGL()
{
eglMakeCurrent(m_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_Surface != EGL_NO_SURFACE)
{
eglDestroySurface(m_Display, m_Surface);
m_Surface = EGL_NO_SURFACE;
}
}
bool MyGame::MakeCurrent_Display_Surface_Context_OpenGL()
{
if (eglMakeCurrent(m_Display, m_Surface, m_Surface, m_Context) == EGL_FALSE)
return false;
return true;
}
bool MyGame::InitGraphic_OpenGL(HWND window)
{
// init Display
m_Display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(m_Display, nullptr, nullptr);
// init Surface
CreateSurfaceFromWindow_OpenGL(window);
// init Context
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2,EGL_NONE };
m_Context = eglCreateContext(m_Display, m_configOpenGL, NULL, contextAttribs);
if (!MakeCurrent_Display_Surface_Context_OpenGL())
return false;
EGLint w, h;
eglQuerySurface(m_Display, m_Surface, EGL_WIDTH, &w);
eglQuerySurface(m_Display, m_Surface, EGL_HEIGHT, &h);
m_Width = w;
m_Height = h;
// Open GL states
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// for alpha color (transparency)
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
return true;
}
void MyGame::CloseGraphic_OpenGL()
{
if (m_Display != EGL_NO_DISPLAY)
{
eglMakeCurrent(m_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_Context != EGL_NO_CONTEXT) {
eglDestroyContext(m_Display, m_Context);
}
if (m_Surface != EGL_NO_SURFACE) {
eglDestroySurface(m_Display, m_Surface);
}
eglTerminate(m_Display);
}
m_Display = EGL_NO_DISPLAY;
m_Context = EGL_NO_CONTEXT;
m_Surface = EGL_NO_SURFACE;
}
C++
Файл my_game.h
#include "opengl_es_windows/include/EGL/egl.h"
#include "opengl_es_windows/include/GLES2/gl2.h"
class MyGame
{
// constructor
public : MyGame();
// fields
protected : EGLDisplay m_Display = EGL_NO_DISPLAY;
protected : EGLSurface m_Surface = EGL_NO_SURFACE;
protected : EGLContext m_Context = EGL_NO_CONTEXT;
protected : EGLConfig m_configOpenGL = nullptr;
protected : int m_Width;
protected : int m_Height;
// events
public : void OnActiveFocus();
public : void OnLostFocus();
public : bool OnHandleTouch();
public : void OnNextTick();
// OpenGL
public : void CreateSurfaceFromWindow_OpenGL(HWND window);
public : void KillSurface_OpenGL();
public : bool MakeCurrent_Display_Surface_Context_OpenGL();
public : bool InitGraphic_OpenGL(HWND window);
public : void CloseGraphic_OpenGL();
public : void DrawGraphic_OpenGL();
};
Нажмем правой клавишей мыши в Visual Studio и добавим my_game.cpp, my_game.h файлы в проект:
Вот так получится:
Шаг 6. Поменяем код в файле ProjectWindowsC++.cpp
C++
Файл ProjectWindowsC++.cpp
#include "framework.h"
#include "ProjectWindowsC++.h"
#include "my_game.h"
#define MAX_LOADSTRING 100
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
ATOM MyRegisterClass(HINSTANCE hInstance);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
constexpr static const float TURN_TIMES_IN_SECONDS = 1.0f / 50.0f; // 50 times per second
bool g_isApplicationClosed = false;
MyGame g_game;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
hInst = hInstance;
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_PROJECTWINDOWSC, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// initialization:
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
g_game.InitGraphic_OpenGL(hWnd);
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PROJECTWINDOWSC));
// Main message loop:
MSG msg;
auto prev_inMilliseconds = GetTickCount64();
while (true)
{
if (g_isApplicationClosed)
break ;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
auto now_inMilliseconds = GetTickCount64();
if (((now_inMilliseconds - prev_inMilliseconds) / 1000.0 /*milliseconds to seconds*/ ) > TURN_TIMES_IN_SECONDS)
{
// my game render
g_game.DrawGraphic_OpenGL();
// my game next tick
g_game.OnNextTick();
}
}
return 0;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PROJECTWINDOWSC));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PROJECTWINDOWSC);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
break ;
}
case WM_DESTROY:
g_isApplicationClosed = true;
g_game.CloseGraphic_OpenGL();
PostQuitMessage(0);
break ;
case WM_SIZE:
break ;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Шаг 7. Запустим программу