LINUX.ORG.RU

Заставить SDL2 работать с шейдерами OpenGL

 , ,


0

1

Пробую разные туториалы по SDL2 + OpenGL. Компиляцией из 2-х туториалов получилось это:

 
#include <string>
#include <iostream>

// OpenGL / glew Headers
#define GL3_PROTOTYPES 1
#include <GL/glew.h>

// SDL2 Headers
#include <SDL2/SDL.h>

std::string programName = "Headerphile SDL2 - OpenGL thing";

// Our SDL_Window ( just like with SDL2 wihout OpenGL)
SDL_Window *mainWindow;
 SDL_Renderer* renderer;

// Our opengl context handle
SDL_GLContext mainContext;

bool SetOpenGLAttributes();
void PrintSDL_GL_Attributes();
void CheckSDLError(int line);
void RunGame();
void Cleanup();

float points[] = {
   0.0f,  0.5f,  0.0f,
   0.5f, -0.5f,  0.0f,
  -0.5f, -0.5f,  0.0f
};

const char* vertex_shader =
"#version 400\n"
"in vec3 vp;"
"void main() {"
"  gl_Position = vec4(vp, 1.0);"
"}";

const char* fragment_shader =
"#version 400\n"
"out vec4 frag_colour;"
"void main() {"
"  frag_colour = vec4(0.5, 0.0, 0.5, 1.0);"
"}";
GLuint shader_programme;
GLuint vbo = 0;
GLuint vao = 0;
GLuint vs;
GLuint fs;

void init_shaders()
{
  shader_programme  = glCreateProgram();
  vs = glCreateShader(GL_VERTEX_SHADER);
  fs = glCreateShader(GL_FRAGMENT_SHADER);
}

void shader_func()
{

init_shaders();
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), points, GL_STATIC_DRAW);


glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);


glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);

glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);



glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
glUseProgram(shader_programme);
glBindVertexArray(vao);
  // draw points 0-3 from the currently bound VAO with current in-use shader
glDrawArrays(GL_TRIANGLES, 0, 3);
}


bool Init()
{
	// Initialize SDL's Video subsystem
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		std::cout << "Failed to init SDL\n";
		return false;
	}

	// Create our window centered at 512x512 resolution
	mainWindow = SDL_CreateWindow(programName.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
		1024, 1024, SDL_WINDOW_OPENGL);

	// Check that everything worked out okay
	if (!mainWindow)
	{
		std::cout << "Unable to create window\n";
		CheckSDLError(__LINE__);
		return false;
	}

	// Create our opengl context and attach it to our window
	mainContext = SDL_GL_CreateContext(mainWindow);

	SetOpenGLAttributes();

	// This makes our buffer swap syncronized with the monitor's vertical refresh
	SDL_GL_SetSwapInterval(1);

	// Init GLEW
	// Apparently, this is needed for Apple. Thanks to Ross Vander for letting me know
	#ifndef __APPLE__
	glewExperimental = GL_TRUE;
	glewInit();
	#endif
     shader_func();
        renderer = SDL_CreateRenderer(mainWindow, -1, 0);

        /* Select the color for drawing. It is set to red here. */
        SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);

        /* Clear the entire screen to our selected color. */
        SDL_RenderClear(renderer);

	return true;
}

bool SetOpenGLAttributes()
{
	// Set our OpenGL version.
	// SDL_GL_CONTEXT_CORE gives us only the newer version, deprecated functions are disabled
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

	// 3.2 is part of the modern versions of OpenGL, but most video cards whould be able to run it
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

	// Turn on double buffering with a 24bit Z buffer.
	// You may need to change this to 16 or 32 for your system
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	return true;
}

int main(int argc, char *argv[])
{
	if (!Init())
		return -1;

	// Clear our buffer with a black background
	// This is the same as :
	// 		SDL_SetRenderDrawColor(&renderer, 255, 0, 0, 255);
	// 		SDL_RenderClear(&renderer);
	//
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);
	SDL_GL_SwapWindow(mainWindow);

	RunGame();

	Cleanup();

	return 0;
}

void RunGame()
{
	bool loop = true;

	while (loop)
	{
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{

                // draw points 0-3 from the currently bound VAO with current in-use shader


			if (event.type == SDL_QUIT)
				loop = false;

			if (event.type == SDL_KEYDOWN)
			{
				switch (event.key.keysym.sym)
				{
				case SDLK_ESCAPE:
					loop = false;
					break;
				case SDLK_r://shader_func();
					// Cover with red and update

					glClearColor(1.0, 0.0, 0.0, 1.0);
					//glClear(GL_COLOR_BUFFER_BIT);
					 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glUseProgram(shader_programme);
            glBindVertexArray(vao);
            glDrawArrays(GL_TRIANGLES, 0, 3);
            //SDL_RenderCopy();
            SDL_RenderPresent(renderer);
					SDL_GL_SwapWindow(mainWindow);

					break;
				case SDLK_g:
					// Cover with green and update
					glClearColor(0.0, 1.0, 0.0, 1.0);
					glClear(GL_COLOR_BUFFER_BIT);
					SDL_GL_SwapWindow(mainWindow);
					break;
				case SDLK_b:
					// Cover with blue and update
					glClearColor(0.0, 0.0, 1.0, 1.0);
					glClear(GL_COLOR_BUFFER_BIT);
					SDL_GL_SwapWindow(mainWindow);
					break;
				default:
					break;
				}
			}

//             glfwPollEvents();
  // put the stuff we've been drawing onto the display
  //glfwSwapBuffers(window);
		}

		// Swap our back buffer to the front
		// This is the same as :
		// 		SDL_RenderPresent(&renderer);
	}
}

void Cleanup()
{
	// Delete our OpengL context
	SDL_GL_DeleteContext(mainContext);

	// Destroy our window
	SDL_DestroyWindow(mainWindow);

	// Shutdown SDL 2
	SDL_Quit();
}

void CheckSDLError(int line = -1)
{
	std::string error = SDL_GetError();

	if (error != "")
	{
		std::cout << "SLD Error : " << error << std::endl;

		if (line != -1)
			std::cout << "\nLine : " << line << std::endl;

		SDL_ClearError();
	}
}

void PrintSDL_GL_Attributes()
{
	int value = 0;
	SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &value);
	std::cout << "SDL_GL_CONTEXT_MAJOR_VERSION : " << value << std::endl;

	SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &value);
	std::cout << "SDL_GL_CONTEXT_MINOR_VERSION: " << value << std::endl;
}

В первом туториале рассказывалось, как прикрутить в SDL OpenGL и он работает: окошко окрашивается в красный цвет по нажатию кнопки.

Во втором - как работать с шейдерами. И хотя код выглядит валидным, он не работает, как минимум, внутри SDL. Никакой визуальной реакции на нажатие кнопки. В чём может быть проблема?

//Все претензии по качеству и объёму приведённого кода вы можете высказать авторам туториалов.

★★★★★

Последнее исправление: next_time (всего исправлений: 1)

Есть ли хоть одна причина не использовать GLFW3?
По теме - не вижу вызова альтернативы glfwMakeContextCurrent и glViewport.

Deleted
()
  1. Как сказано выше, ты должен установить SDL_GL_CONTEXT_MAJOR_VERSION и SDL_GL_CONTEXT_MINOR_VERSION в значения 4 и 0 соответственно.
  2. Вызов SetOpenGLAttributes должен идти перед функцией SDL_GL_CreateContext, а не после.
  3. И самое главное - одновременное использование SDL_Renderer'а и OpenGL в одной программе не рекомендуется. Следовательно, нужно удалить SDL_CreateRenderer, SDL_RenderClear и другие вызовы функций, связанные с переменной renderer.

После проведенных данных манипуляций программа заработала (по крайней мере на моем компьютере).

goto-vlad
()
Ответ на: комментарий от Deleted

Ещё не вижу что бы ты просил контекст версии 4.x

// 3.2 is part of the modern versions of OpenGL, but most video cards whould be able to run it
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
linuhs_user
()
Ответ на: комментарий от goto-vlad

Спасибо. Тоже заработало. С единственной разницей: т.к. моя видеокарта не поддерживает OpenGL 4.0, прописал

не SDL_GL_CONTEXT_MAJOR_VERSION и SDL_GL_CONTEXT_MINOR_VERSION, а наоборот, #version 330 вместо #version 400 в шейдере.

при этом, даже оставил SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

next_time ★★★★★
() автор топика
Последнее исправление: next_time (всего исправлений: 1)
Ответ на: комментарий от linuhs_user

не, там вместо этого версию в шейдере надо было поменять

next_time ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.