It appears if I drag-resize fast enough, the window itself is created by subclassing qwindow and making an openGLcontext on it
Code:
#include <QGuiApplication>
#include <QOpenGLContext>
#include <QWindow>
#include <QOpenGLFunctions_3_3_Core>
#include <stdio.h>
class OpenGLWindow : public QWindow, protected QOpenGLFunctions_3_3_Core{
public:
explicit OpenGLWindow();
~OpenGLWindow();
virtual void render();
bool isWindowInitialized;
void exposeEvent(QExposeEvent *event);
bool event(QEvent *event);
private:
QOpenGLContext* ctx;
QSurfaceFormat* fmt;
bool isGLInitialized;
GLuint VertexArrayID;
GLuint buffer1;
GLuint ProgramID;
};
bool OpenGLWindow::event(QEvent *event)
{
switch (event->type()) {
case QEvent::UpdateRequest:
render();
return true;
case QEvent::Close:
glDisableVertexAttribArray(0);
glDeleteBuffers(1, &buffer1);
glDeleteVertexArrays(1, &VertexArrayID);
glDeleteProgram(ProgramID);
return QWindow::event(event);
case QEvent::Resize:
if(isWindowInitialized && isGLInitialized)glViewport(0,0,width(),height());
return QWindow::event(event);
default:
return QWindow::event(event);
}
}
void OpenGLWindow::exposeEvent(QExposeEvent *event)
{
Q_UNUSED(event);
if (isExposed())render();
}
OpenGLWindow::OpenGLWindow()
:ctx(new QOpenGLContext)
,fmt(new QSurfaceFormat)
,isGLInitialized(0)
{
setSurfaceType(OpenGLSurface);
fmt->setRenderableType(QSurfaceFormat::OpenGL);
fmt->setVersion(3,3);
resize(640,480);
fmt->setProfile(QSurfaceFormat::CoreProfile);
setFormat(*fmt);
ctx->setFormat(*fmt);
ctx->create();
}
OpenGLWindow::~OpenGLWindow()
{}
void OpenGLWindow::render(){
//if(Image::isWindowInitialized || isExposed())return;
if(!isGLInitialized){
ctx->makeCurrent(this);
initializeOpenGLFunctions();
GLuint vsID = glCreateShader(GL_VERTEX_SHADER);
GLuint fsID = glCreateShader(GL_FRAGMENT_SHADER);
const char* vs="#version 330 core\n layout(location = 0) in vec3 vertexPosition_modelspace; \n void main(){ gl_Position.xyz = vertexPosition_modelspace; gl_Position.w = 1.0;}";
const char* fs="#version 330 core\n out vec4 color;\n void main(){ color = vec4(1,0,0,1);}";
glShaderSource(vsID, 1, &vs , NULL);
glCompileShader(vsID);
GLint isCompiled = 0;
glGetShaderiv(vsID, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE){
GLint maxLength = 0;
glGetShaderiv(vsID, GL_INFO_LOG_LENGTH, &maxLength);
char info[512];
glGetShaderInfoLog(vsID, maxLength, &maxLength, info);
printf("%s",info);}
glShaderSource(fsID, 1, &fs , NULL);
glCompileShader(fsID);
glGetShaderiv(fsID, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE){
GLint maxLength = 0;
glGetShaderiv(fsID, GL_INFO_LOG_LENGTH, &maxLength);
char info[512];
glGetShaderInfoLog(fsID, maxLength, &maxLength, info);
printf("%s",info);
}
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, vsID);
glAttachShader(ProgramID, fsID);
glLinkProgram(ProgramID);
glDeleteShader(vsID);
glDeleteShader(fsID);
static const GLfloat data1[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
glGenBuffers(1, &buffer1);
glBindBuffer(GL_ARRAY_BUFFER,buffer1);
glBufferData(GL_ARRAY_BUFFER, sizeof(data1),data1, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0 ,3 ,GL_FLOAT ,GL_FALSE,0 ,(void*)0 );
glClearColor(1.0f, 0.0f, 0.4f,1.0f);
glUseProgram(ProgramID);
glViewport(0,0,width(),height());
isGLInitialized=true;
}
if(isExposed()){
glClear( GL_COLOR_BUFFER_BIT );
glDrawArrays(GL_TRIANGLES, 0, 3);
ctx->swapBuffers(this);
}
}
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
OpenGLWindow* win = new OpenGLWindow();
win->show();
win->isWindowInitialized=true;
return app.exec();
}
I'm using Qt 5.4.2 on Qt Creator 3.4.1
Kit : Desktop Qt 5.4.2 MSVC2013 64bit
I'm kida lost here since i've never used openGL in qt and it's hard for me to picture where the problem might originate
Try setting a combination of any of the following attributes:
this->setAttribute(Qt::WA_OpaquePaintEvent, true);
this->setAttribute(Qt::WA_PaintOnScreen, true);
this->setAttribute(Qt::WA_DontCreateNativeAncestors, true);
this->setAttribute(Qt::WA_NativeWindow, true);
this->setAttribute(Qt::WA_NoSystemBackground, true);
this->setAttribute(Qt::WA_MSWindowsUseDirect3D, true);
this->setAutoFillBackground(false);
Related
I try to learn OpenGL context object sharing so I write a demo about object sharing:
#include <unistd.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include<iostream>
using namespace std;
const char* vertex_shader_text =
"#version 330 core\n"
"layout(location = 0) in vec2 vPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(vPos, 1, 1);\n"
"}\n";
const char* fragment_shader_text =
"#version 330 core\n"
"uniform vec3 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(color,1.0);\n"
"}\n";
GLuint loadShader(const char* vs, const char* fs) {
const GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vs, NULL);
glCompileShader(vertex_shader);
const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fs, NULL);
glCompileShader(fragment_shader);
const GLuint programID = glCreateProgram();
glAttachShader(programID, vertex_shader);
glAttachShader(programID, fragment_shader);
glLinkProgram(programID);
return programID;
}
float colors[2][3] = {
{1.0, 1.0, 0.0}, {1.0, 0.0, 1.0}
};
static void key_callback(GLFWwindow* window, int key, int scancode, int action,
int mods) {
if (action == GLFW_PRESS && key == GLFW_KEY_ESCAPE)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
void character_callback(GLFWwindow* window, unsigned int codepoint) {
printf("character_callback: %p, codepoint:%c\n", window,codepoint);
float r[3] = {1.0f, 0.0f, 0.0f};
float g[3] = {0.0f, 1.0f, 0.0f};
float b[3] = {0.0f, 0.0f, 1.0f};
if (codepoint == '1') {
for (int i = 0; i < 3; i++) {
colors[1][i] = r[i];
}
} else if (codepoint == '2') {
for (int i = 0; i < 3; i++) {
colors[1][i] = g[i];
}
}
if (codepoint == '3') {
for (int i = 0; i < 3; i++) {
colors[1][i] = b[i];
}
}
}
int main(int argc, char** argv) {
const char* description;
GLFWwindow* windows[2];
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
{
windows[0] = glfwCreateWindow(300, 300, "window1", NULL, NULL);
glfwSetCharCallback(windows[0], character_callback);
glfwMakeContextCurrent(windows[0]);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
}
GLuint vao[2];
glGenVertexArrays(1, &vao[0]);
GLuint vbo;
glGenBuffers(1, &vbo);
const GLfloat vertices[] = {-1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f};
const GLuint program = loadShader(vertex_shader_text, fragment_shader_text);
{
glUseProgram(program);
glBindVertexArray(vao[0]);
{
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
}
// glBindVertexArray(0);
}
// window2
{
windows[1] = glfwCreateWindow(300, 300, "window2", nullptr, windows[0]);
glfwSetCharCallback(windows[1], character_callback);
glfwMakeContextCurrent(windows[1]);
{
glUseProgram(program);
glGenVertexArrays(1, &vao[1]);
glBindVertexArray(vao[1]);
{
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
}
// glBindVertexArray(0);
}
}
for (int i = 0; i < 2; i++) {
glfwSetKeyCallback(windows[i], key_callback);
glfwMakeContextCurrent(windows[i]);
glClearColor(colors[0][0], colors[0][1], colors[0][2], 1.0);
for (int k = 0; k < 3; k++) {
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(windows[i]);
}
}
int color_pos = glGetUniformLocation(program, "color");
glfwMakeContextCurrent(0);
// ==========step 2============
while (!glfwWindowShouldClose(windows[0]) &&
!glfwWindowShouldClose(windows[1])) {
for (int i = 0; i < 2; i++) {
glfwPollEvents();
glfwMakeContextCurrent(windows[i]);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao[i]);
glUniform3f(color_pos, colors[1][0], colors[1][1], colors[1][2]); //??? I change two window triangle color, why only one window work when i click the button 1,2,3 ?
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(windows[i]);
glBindVertexArray(0);
glfwMakeContextCurrent(0);
}
}
glfwTerminate();
exit(EXIT_SUCCESS);
}
I expect the each window draw the same triangle with same color, when I click key 1,2 and 3, the two window will change color to red,green and blue at the same time.
It's working on ubuntu20.04, but not working on fedora36, only one window will change the color, the other one do not.
Why does only one window's triangle color change and the another one not?
I try to use gdb to debug the program, but it's seem too difficult to figure out.
My environment is:
jack#fedora
------------
OS: Fedora release 36 (Thirty Six) x86_64
Host: 20FBA05VCD ThinkPad X1 Carbon 4th
Kernel: 5.19.8-200.fc36.x86_64
Uptime: 11 days, 14 hours, 17 mins
Packages: 6001 (rpm), 58 (flatpak), 12 (snap)
Shell: bash 5.1.16
Resolution: 1920x1080
DE: GNOME 42.5
WM: Mutter
WM Theme: Adwaita
Theme: Adwaita [GTK2/3]
Icons: Adwaita [GTK2/3]
Terminal: gnome-terminal
CPU: Intel i5-6200U (4) # 2.800GHz
GPU: Intel Skylake GT2 [HD Graphics 520]
Memory: 6008MiB / 6866MiB
Both the vertex and fragment shader seem to be compiling and the window appears and is given the clear color but I cannot get the triangle to render. I have tried to just use the glBegin(); vertex(); glEnd(); as an alternative but this also resulted in no rendered triangle.
main.c
#include <stdio.h>
#include <unistd.h>
#include <gfx/shader.h>
#include <gfx/vbo.h>
#include <gfx/vao.h>
GLfloat vertices[] = {
0.0f,1.0f,0.0f,
1.0f,1.0f,0.0f,
-1.0f,-1.0f,0.0f
};
int main(void){
if(!glfwInit()){
fprintf(stderr, "Unable to init GLFW.\n");
exit(1);
}
GLFWwindow *win;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
win = glfwCreateWindow(SCREENWIDTH, SCREENHEIGHT, "Terraria", NULL, NULL);
if(win==NULL){
fprintf(stderr, "Error creating opengl window\n");
glfwTerminate();
exit(1);
}
glfwMakeContextCurrent(win);
if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
fprintf(stderr, "Unable to init glad\n");
glfwTerminate();
exit(1);
}
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(win, frame_buffer_size_cb);
struct Shader s = create_shader("resources/shaders/vec2.vs", "resources/shaders/vec2.fs");
uint32_t vaoID, vboID;
glGenVertexArrays(1, &vaoID);
glBindVertexArray(vaoID);
glGenBuffers(1, &vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(vboID, 9*sizeof(GLfloat), vertices, GL_STATIC_DRAW);
while(!glfwWindowShouldClose(win)){
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(s.sh);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
3*sizeof(GLfloat),
(void*)0
);
glDrawArrays(GL_TRIANGLES, 0,3);
glDisableVertexAttribArray(0);
glfwSwapBuffers(win);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
shader.h
#include <gfx/gfx.h>
struct Shader{
uint32_t sh;
uint32_t vsh;
uint32_t fsh;
};
struct Shader create_shader(const char *vs_path, const char *fs_path);
shader.c
#include <gfx/shader.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
static uint32_t _compile(int8_t id, const char *path, uint16_t type){
uint32_t sh; //Shader handle or ID
FILE *fp = fopen(path, "rb"); //Open the shader source code file
long sz = file_size(fp); //Get the file size
char *shaderSource; //Create object to holder shader source code
shaderSource = calloc(sz+1, 1);
fread(shaderSource, 1, sz, fp); //Read the shader source code into new buffer
fclose(fp);
assert(strlen(shaderSource)>0);
sh = glCreateShader(type);
glShaderSource(sh, 1, (const GLchar **)&shaderSource, NULL);
glCompileShader(sh);
int success;
char infoLog[512];
glGetShaderiv(sh, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(sh, 512, NULL, infoLog);
printf("Unable to compile shader id %d\n", id);
}
free(shaderSource);
return sh;
}
struct Shader create_shader(const char *vs_path, const char *fs_path){
struct Shader h;
h.vsh = _compile(1,vs_path, GL_VERTEX_SHADER);
h.fsh = _compile(0,fs_path, GL_FRAGMENT_SHADER);
h.sh = glCreateProgram();
glAttachShader(h.sh, h.vsh);
glAttachShader(h.sh, h.fsh);
glLinkProgram(h.sh);
// check for linking errors
int success;
char infoLog[512];
glGetProgramiv(h.sh, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(h.sh, 512, NULL, infoLog);
printf("Unable to link gl program\n");
}
glDetachShader(h.sh, h.vsh);
glDetachShader(h.sh, h.fsh);
glDeleteShader(h.vsh);
glDeleteShader(h.fsh);
return h;
}
vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;
void main(){
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
fragment shader
#version 330 core
out vec4 FragColor;
void main(){
FragColor = vec4(1.0,1.0,1.0,1.0);
}
I have found the answer. If you look really closely in main, it seems that you are actually supposed to call glBindBuffer to the macro GL_ARRAY_BUFFER and not to the vbo handle like I thought. Fixing this caused my program to function. Also my window hints were not taking effect because I was calling them after creating the window.
I have created a simple wxGLCanvas for demonstrating OpenGl using wxWidgets. The demo is working fine except when resizing the window the memory usage increases from a few megabytes to almost 400 megabytes and it stays there and doesn't decrease, here are the code snippets.
// ctor
TriangleCanvas::TriangleCanvas(wxWindow* parent, wxGLAttributes& attribList)
: wxGLCanvas(parent, attribList, wxID_ANY, { 0,0 }, wxDefaultSize),
m_vbo(0), m_vao(0), ctx_attr(new wxGLContextAttrs)
{
ctx_attr->CoreProfile().OGLVersion(4, 3).EndList();
m_context = new wxGLContext(this, NULL, ctx_attr);
Bind(wxEVT_PAINT, &TriangleCanvas::OnPaint, this);
Bind(wxEVT_SIZE, &TriangleCanvas::Resize, this);
}
// Paint method
void TriangleCanvas::OnPaint(wxPaintEvent& event)
{
wxPaintDC(this);
SetCurrent(*m_context);
shader->use();
// set background to black
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw the graphics
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glFlush();
SwapBuffers();
}
void TriangleCanvas::Resize(wxSizeEvent& event) {
event.Skip();
glViewport(0, 0, event.GetSize().x, event.GetSize().y);
if (!setup) {
InitializeGLEW();
SetupGraphics();
}
}
I think the best way to use wxGLCanvas with an extension loader is to use a helper class and keep all OpenGL drawing in the cpp portion of that helper class.
For example, here is a small helper class for drawing a triangle:
glhelper.h
#ifndef GLHELPER_H_INCLUDED
#define GLHELPER_H_INCLUDED
class GLHelper
{
public:
bool InitGlew();
void Render();
void SetSize(int w, int h);
bool InitData();
void Cleanup();
private:
unsigned int m_VBO, m_VAO, m_shaderProgram;
};
#endif // GLHELPER_H_INCLUDED
glhelper.cpp
#include <GL/glew.h>
#ifdef __WXMSW__
#include <GL/wglew.h>
#elif defined(__WXGTK__)
#include <GL/glxew.h>
#endif // defined
#include "glhelper.h"
static const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
static const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
bool GLHelper::InitGlew()
{
GLenum initStatus = glewInit();
return initStatus == GLEW_OK;
}
bool GLHelper::InitData()
{
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
int success;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
return false;
}
// fragment shader
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
return false;
}
// link shaders
m_shaderProgram = glCreateProgram();
glAttachShader(m_shaderProgram, vertexShader);
glAttachShader(m_shaderProgram, fragmentShader);
glLinkProgram(m_shaderProgram);
// check for linking errors
glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
return false;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
//unsigned int VBO, VAO;
glGenVertexArrays(1, &m_VAO);
glGenBuffers(1, &m_VBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s),
// and then configure vertex attributes(s).
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// note that this is allowed, the call to glVertexAttribPointer registered
//VBO as the vertex attribute's bound vertex buffer object so afterwards we
//can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally
//modify this VAO, but this rarely happens. Modifying other VAOs requires a
//call to glBindVertexArray anyways so we generally don't unbind VAOs (nor
// VBOs) when it's not directly necessary.
glBindVertexArray(0);
return true;
}
void GLHelper::Cleanup()
{
glDeleteVertexArrays(1, &m_VAO);
glDeleteBuffers(1, &m_VBO);
glDeleteProgram(m_shaderProgram);
}
void GLHelper::Render()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(m_shaderProgram);
glBindVertexArray(m_VAO);
// seeing as we only have a single VAO there's no need to bind it every
//time, but we'll do so to keep things a bit more organized
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void GLHelper::SetSize(int width, int height)
{
glViewport(0, 0, width, height);
}
And here is a short demo that uses this helper class to draw the trinagle.
demo.cpp
#include "wx/wx.h"
#include <wx/glcanvas.h>
#include "glhelper.h"
class wxGlewFrame: public wxFrame
{
public:
wxGlewFrame(wxWindow*);
~wxGlewFrame();
private:
void OnCanvasSize(wxSizeEvent&);
void OnCanvasPaint(wxPaintEvent&);
void InitGL();
wxGLCanvas* m_canvas;
wxGLContext* m_context;
GLHelper m_helper;
};
wxGlewFrame::wxGlewFrame(wxWindow* parent)
: wxFrame(parent, wxID_ANY, wxString())
{
// Create the canvas and context.
#if wxCHECK_VERSION(3,1,0)
// These settings should work with any GPU from the last 10 years.
wxGLAttributes dispAttrs;
dispAttrs.PlatformDefaults().RGBA().DoubleBuffer().EndList();
wxGLContextAttrs cxtAttrs;
cxtAttrs.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList();
m_canvas = new wxGLCanvas(this, dispAttrs);
m_context = new wxGLContext(m_canvas, NULL, &cxtAttrs);
if ( !m_context->IsOK() )
{
SetTitle("Failed to create context.");
return;
}
#else
int dispAttrs[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_CORE_PROFILE,
WX_GL_MAJOR_VERSION ,3, WX_GL_MINOR_VERSION, 3, 0 };
m_canvas = new wxGLCanvas(this, wxID_ANY, dispAttrs);
m_context = new wxGLContext(m_canvas, NULL);
// Unfortunately, there doesn't seem to be any way to check if the
// context is ok prior to wxWidgets 3.1.0.
#endif // wxCHECK_VERSION
// On Linux, we must delay delay initialization until the canvas has
// been full created. On windows, we can finish now.
#ifdef __WXMSW__
InitGL();
#elif defined(__WXGTK__)
m_canvas->Bind(wxEVT_CREATE, [this](wxWindowCreateEvent&){InitGL();});
#endif // defined
}
wxGlewFrame::~wxGlewFrame()
{
m_helper.Cleanup();
delete m_context;
}
void wxGlewFrame::OnCanvasSize(wxSizeEvent& event)
{
wxSize sz = event.GetSize();
m_helper.SetSize(sz.GetWidth(), sz.GetHeight());
event.Skip();
}
void wxGlewFrame::OnCanvasPaint(wxPaintEvent&)
{
wxPaintDC dc(m_canvas);
m_helper.Render();
m_canvas->SwapBuffers();
}
void wxGlewFrame::InitGL()
{
// First call SetCurrent or GL initialization will fail.
m_context->SetCurrent(*m_canvas);
// Initialize GLEW.
bool glewInialized = m_helper.InitGlew();
if ( !glewInialized )
{
SetTitle("Failed it initialize GLEW.");
return;
}
SetTitle("Context and GLEW initialized.");
// Initialize the triangle data.
m_helper.InitData();
// Bind event handlers for the canvas. Binding was delayed until OpenGL was
// initialized because these handlers will need to call OpenGL functions.
m_canvas->Bind(wxEVT_SIZE, &wxGlewFrame::OnCanvasSize, this);
m_canvas->Bind(wxEVT_PAINT, &wxGlewFrame::OnCanvasPaint, this);
}
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
wxGlewFrame* frame = new wxGlewFrame(NULL);
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
(This is basically the Hello Triangle sample from learnopengl.com except rewritten to use wxGLCanvas and GLEW instead of GLFW and GLAD.
This takes up about 19MB of memory on my system and only increases up to about 24 or 25MB when resizing. That might sound like a lot for such a simple program, but the running the official "Hello Triangle" sample uses 26MB. So I think the memory usage is about what should be expected.
I am writing a openGL program(C++) which draws a ground with two 3D objects above it. The programming tool I use is Xcode version 8.0(8A218a)(OSX 10.11.6).
my code(main.cpp):
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <fstream>
using namespace std;
using glm::vec3;
using glm::mat4;
GLint programID;
//initialize all OpenGL objects
GLuint groundVAO, groundVBO, groundEBO; //ground
bool checkStatus( //OK
GLuint objectID,
PFNGLGETSHADERIVPROC objectPropertyGetterFunc,
PFNGLGETSHADERINFOLOGPROC getInfoLogFunc,
GLenum statusType)
{
GLint status;
objectPropertyGetterFunc(objectID, statusType, &status);
if (status != GL_TRUE)
{
GLint infoLogLength;
objectPropertyGetterFunc(objectID, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar* buffer = new GLchar[infoLogLength];
GLsizei bufferSize;
getInfoLogFunc(objectID, infoLogLength, &bufferSize, buffer);
cout << buffer << endl;
delete[] buffer;
return false;
}
return true;
}
bool checkShaderStatus(GLuint shaderID) //OK
{
return checkStatus(shaderID, glGetShaderiv, glGetShaderInfoLog, GL_COMPILE_STATUS);
}
bool checkProgramStatus(GLuint programID) //OK
{
return checkStatus(programID, glGetProgramiv, glGetProgramInfoLog, GL_LINK_STATUS);
}
string readShaderCode(const char* fileName) //OK
{
ifstream meInput(fileName);
if (!meInput.good())
{
cout << "File failed to load..." << fileName;
exit(1);
}
return std::string(
std::istreambuf_iterator<char>(meInput),
std::istreambuf_iterator<char>()
);
}
void installShaders() //OK
{
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
const GLchar* adapter[1];
//adapter[0] = vertexShaderCode;
string temp = readShaderCode("VertexShaderCode.glsl");
adapter[0] = temp.c_str();
glShaderSource(vertexShaderID, 1, adapter, 0);
//adapter[0] = fragmentShaderCode;
temp = readShaderCode("FragmentShaderCode.glsl");
adapter[0] = temp.c_str();
glShaderSource(fragmentShaderID, 1, adapter, 0);
glCompileShader(vertexShaderID);
glCompileShader(fragmentShaderID);
if (!checkShaderStatus(vertexShaderID) ||
!checkShaderStatus(fragmentShaderID))
return;
programID = glCreateProgram();
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
glLinkProgram(programID);
if (!checkProgramStatus(programID))
return;
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
glUseProgram(programID);
}
void keyboard(unsigned char key, int x, int y)
{
//TODO:
}
void sendDataToOpenGL()
{
//TODO:
//create solid objects here and bind to VAO & VBO
//Ground, vertices info
const GLfloat Ground[]
{
-5.0f, +0.0f, -5.0f, //0
+0.498f, +0.898, +0.0f, //grass color
+5.0f, +0.0f, -5.0f, //1
+0.498f, +0.898, +0.0f,
+5.0f, +0.0f, +5.0f, //2
+0.498f, +0.898, +0.0f,
-5.0f, +0.0f, +5.0f
};
GLushort groundIndex[] = {1,2,3, 1,0,3};
//Pass ground to vertexShader
//VAO
glGenVertexArrays(1, &groundVAO);
glBindVertexArray(groundVAO);
//VBO
glGenBuffers(1, &groundVBO);
glBindBuffer(GL_ARRAY_BUFFER, groundVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Ground), Ground, GL_STATIC_DRAW);
//EBO
glGenBuffers(1, &groundEBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, groundEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(groundIndex), groundIndex, GL_STATIC_DRAW);
//connectToVertexShader
glEnableVertexAttribArray(0); //position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, 0);
glEnableVertexAttribArray(1); //color
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (char*)(sizeof(float)*3));
}
void paintGL(void)
{
//TODO:
//render your objects and control the transformation here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//translate model
glm::mat4 modelTransformMatrix = glm::translate(glm::mat4(), vec3(+0.0f, +0.0f, -3.0f));
//perspective view
glm::mat4 projectionMatrix = glm::perspective(+40.0f, +1.0f, +1.0f, +60.0f);
//ultimate matrix
glm::mat4 ultimateMatrix;
//register location on the graphics cards
GLint ultimateMatrixUniformLocation = glGetUniformLocation(programID, "ultimateMatrix");
/*GLint modelTransformMatrixUniformLocation = glGetUniformLocation(programID, "modelTransformMatrix");
GLint projectionMatrixUniformLocation = glGetUniformLocation(programID, "projectionMatrix");*/
//drawing the ground
/*glUniformMatrix4fv(modelTransformMatrixUniformLocation, 1, GL_FALSE, &modelTransformMatrix[0][0]);
glUniformMatrix4fv(projectionMatrixUniformLocation, 1, GL_FALSE, &projectionMatrix[0][0]);*/
glBindVertexArray(groundVAO);
ultimateMatrix = projectionMatrix * modelTransformMatrix;
glUniformMatrix4fv(ultimateMatrixUniformLocation, 1, GL_FALSE, &ultimateMatrix[0][0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glFlush();
glutPostRedisplay();
}
void initializedGL(void) //run only once
{
glewInit();
glEnable(GL_DEPTH_TEST);
sendDataToOpenGL();
installShaders();
}
int main(int argc, char *argv[])
{
/*Initialization*/
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutCreateWindow("Try");
glutInitWindowSize(700, 700);
//const GLubyte* glversion = glGetString(GL_VERSION);
/*Register different CALLBACK function for GLUT to response
with different events, e.g. window sizing, mouse click or
keyboard stroke */
initializedGL();
//glewExperimental = GL_TRUE;
glutDisplayFunc(paintGL);
glutKeyboardFunc(keyboard);
/*Enter the GLUT event processing loop which never returns.
it will call different registered CALLBACK according
to different events. */
//printf("OpenGL ver: %s\n", glversion);
glutMainLoop();
return 0;
}
VertexShaderCode.glsl:
#version 430 // GLSL version your computer supports
in layout(location=0) vec3 position;
in layout(location=1) vec3 vertexColor;
uniform mat4 ultimateMatrix;
out vec3 theColor;
void main()
{
vec4 v = vec4(position, 1.0);
gl_Position = ultimateMatrix * v;
theColor = vertexColor;
}
FragmentShaderCode.glsl:
#version 430 //GLSL version your computer supports
out vec4 theColor2;
in vec3 theColor;
void main()
{
theColor2 = vec4(theColor, 1.0);
}
Functions: checkStatus, checkShaderStatus, checkProgramStatus, readShaderCode, installShaders should be all fine.
void keyboard() can be ignored since I havent implemented it yet(just for keyboard control).
I implemented the object "Ground" in sendDataToOpenGL(). But when I compiled and ran the program, "thread 1: exc_bad_access (code =1, address=0x0)" occured in the line of VAO:
And the pop-out window is just a white screen instead of a green grass(3d).
I have tried a method which was provided in other stackoverflow post: using glewExperimental = GL_TRUE;. I didnt see any errors by using that, but the popout screen vanished immediately just after it appeared. It seems that it couldnt help the problem.
Can someone give me a help? Thank you!
glGenVertexArrays is available in since OpenGL version 3.0. If vertex array objects are supported can be checked by glewGetExtension("GL_ARB_vertex_array_object").
Glew can enable additional extensions by glewExperimental = GL_TRUE;. See the GLEW documantation which says:
GLEW obtains information on the supported extensions from the graphics driver. Experimental or pre-release drivers, however, might not report every available extension through the standard mechanism, in which case GLEW will report it unsupported. To circumvent this situation, the glewExperimental global switch can be turned on by setting it to GL_TRUE before calling glewInit(), which ensures that all extensions with valid entry points will be exposed.
Add this to your code:
glewExperimental = GL_TRUE;
glewInit();
I'm doing my first steps in OpenGl Shader base programming and computer graphics. I'm trying the following example, but when I try to compile the project I got the following error:
fragment shader failed to link. vertex shader failed to link.
ERROR: Not all shaders has valid object code
i tried running the program in Visual Studio 2012 and 2010. glut library version is 3.7 and glew library version is 1.10.0. what is the problem?
.cpp Program
#include <stdio.h>
#include <stdlib.h>
#include <glew.h>
#include <glut.h>
#include <gl.h>
#pragma comment(lib,"glew32.lib")
#define NoP 50000
GLuint InitShader(char *, char *);
void mydisplay();
struct points
{ GLfloat x,y,z;
};
void init();
void Sierpinski(points Num[]);
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE|GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutInitWindowPosition(0,0);
glutCreateWindow("Sierpinski 3D");
glewInit();
init();
glEnable(GL_DEPTH_TEST);
glutDisplayFunc(mydisplay);
glutMainLoop();
}
void init()
{
points Num[NoP];
Sierpinski(Num);
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);//set the color for clearing the display
glPointSize(2); // set the point size
// Creating a program object containing shader files
GLuint program;
program = InitShader("vshader.glsl","fshader.glsl");
glUseProgram(program);
//Creating a buffer object containing Sirepinski verteces data
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Num), Num, GL_STATIC_DRAW);
//Make a conncetion between data in object buffer and "vPosition in vertex shader
GLuint location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray ( location );
glVertexAttribPointer( location, 3, GL_FLOAT, GL_FALSE,0, 0);//BUFFER_OFFSET(0));
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //the clear call will affect the color buffer
glDrawArrays(GL_POINTS,0,NoP);//Rendering verteces data
glFlush(); //Empty all commands buffer, causing all issued commands to be executed as quickly as they are accepted by the actual rendering engine
}
static char * ReadShaderSource(char * ShaderFile)
{
FILE *fp;
fp = fopen(ShaderFile,"rt");
if (!fp) return NULL;
long size=0;
while (!feof(fp))
{
fgetc (fp);
size++;
}
size--;//EOF should not be counted
fseek(fp, 0, SEEK_SET);
char * buf= new char[size + 1];
fread(buf, 1, size,fp);
buf[size]=0;// string is NULL terminated
fclose(fp);
return buf;
}
GLuint InitShader(char * vShaderFile, char * fShaderFile)
{
char * svs, * sfs;
GLuint program, VertexShader, FragmentShader;
program = glCreateProgram();
VertexShader = glCreateShader(GL_VERTEX_SHADER);
svs=ReadShaderSource(vShaderFile);
glShaderSource(VertexShader,1,(const GLchar **)&svs,NULL);
glCompileShader(VertexShader);
// reading GLSL compiler error messages for vertex shader
GLint compiled;
glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &compiled);
if(!compiled)
{ printf("/n failed to compile");
GLint logSize;
glGetShaderiv(VertexShader, GL_INFO_LOG_LENGTH,&logSize);
char * logMsg = new char[logSize];
glGetShaderInfoLog(VertexShader, logSize, NULL, logMsg);
printf("\n %s",logMsg);
delete [] logMsg;
getchar();
exit(EXIT_FAILURE);
}
FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
sfs = ReadShaderSource(fShaderFile);
glShaderSource(FragmentShader, 1, (const GLchar **)&sfs, NULL);
glCompileShader(FragmentShader);
// reading GLSL compiler error messages for fragment shader
glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &compiled);
if(!compiled)
{ printf("\n failed to compile");
GLint logSize2;
glGetShaderiv(FragmentShader, GL_INFO_LOG_LENGTH,&logSize2);
char * logMsg2 = new char[logSize2];
glGetShaderInfoLog(FragmentShader, logSize2, NULL, logMsg2);
printf("\n %s",logMsg2);
delete [] logMsg2;
getchar();
exit(EXIT_FAILURE);
}
glAttachShader(program,VertexShader);
glAttachShader(program, FragmentShader);
glLinkProgram(program);
// reading GLSL linker error messages for program object
GLint linked;
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if(!linked)
{ printf("/n failed to link");
GLint logSize;
glGetProgramiv(program, GL_INFO_LOG_LENGTH,&logSize);
char * logMsg = new char[logSize];
glGetProgramInfoLog(program, logSize, NULL, logMsg);
printf("\n %s",logMsg);
delete [] logMsg;
getchar();
exit(EXIT_FAILURE);
}
glUseProgram(program);
return program;
}
void Sierpinski(points Num[])
{
int j;
points Vertices[4]={{-1.0,-1.0, -1.0},{1.0,-1.0,-1.0},{0.0,1.0,-1.0},{0.0,0.0,1.0}};
Num[0].x = 0;
Num[0].y = 0;
Num[0].z = 0;
for(int i=1;i<NoP;i++)
{
j = rand() % 4;
Num[i].x = (Vertices[j].x + Num[i - 1].x)/2;
Num[i].y = (Vertices[j].y + Num[i - 1].y)/2;
Num[i].z = (Vertices[j].z + Num[i - 1].z)/2;
}
}
vshader.glsl
#version 130
in vec4 vPosition;
out vec4 color;
void main()
{
gl_Position = vPosition;
color = vPosition;
}
fshader.glsl
#version 130
in vec4 color;
void main()
{
gl_FragColor = vec4((1.0 + color.xyz)/2.0,1.0);
}
Seems to work fine:
#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>
void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 17 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
exit( -1 );
}
void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
GLuint LoadProgram( const char* vert, const char* geom, const char* frag )
{
GLuint prog = glCreateProgram();
if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
#define GLSL(version, shader) "#version " #version "\n" #shader
const char* vert = GLSL
(
130,
in vec4 vPosition;
out vec4 color;
void main()
{
gl_Position = vPosition;
color = vPosition;
}
);
const char* frag = GLSL
(
130,
precision mediump float;
in vec4 color;
void main()
{
gl_FragColor = vec4((1.0 + color.xyz)/2.0,1.0);
}
);
#define NoP 50000
struct points
{
GLfloat x,y,z;
};
void Sierpinski(points Num[])
{
int j;
points Vertices[4]={{-1.0,-1.0, -1.0},{1.0,-1.0,-1.0},{0.0,1.0,-1.0},{0.0,0.0,1.0}};
Num[0].x = 0;
Num[0].y = 0;
Num[0].z = 0;
for(int i=1;i<NoP;i++)
{
j = rand() % 4;
Num[i].x = (Vertices[j].x + Num[i - 1].x)/2;
Num[i].y = (Vertices[j].y + Num[i - 1].y)/2;
Num[i].z = (Vertices[j].z + Num[i - 1].z)/2;
}
}
void init()
{
points Num[NoP];
Sierpinski(Num);
GLuint program = LoadProgram( vert, NULL, frag );
glUseProgram(program);
//Creating a buffer object containing Sirepinski verteces data
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Num), Num, GL_STATIC_DRAW);
//Make a conncetion between data in object buffer and "vPosition in vertex shader
GLuint location = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray ( location );
glVertexAttribPointer( location, 3, GL_FLOAT, GL_FALSE,0, 0);//BUFFER_OFFSET(0));
}
void mydisplay()
{
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);//set the color for clearing the display
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //the clear call will affect the color buffer
glPointSize(2); // set the point size
glDrawArrays(GL_POINTS,0,NoP);//Rendering verteces data
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutInitWindowPosition(0,0);
glutCreateWindow("Sierpinski 3D");
glewInit();
init();
glEnable(GL_DEPTH_TEST);
glutDisplayFunc(mydisplay);
glutMainLoop();
}
Make sure you use FreeGLUT, Nate's GLUT is way, way old.