Continuously render Gtk::GLArea in gtkmm - c++

I've followed a gtkmm4 + opengl example, the window loads and displays without any errors and renders one frame but then seems to ignore my queue_render() and queue_draw() calls as evidenced by the print statements in the console. I've set auto render to true as well.
#include <iostream>
#include <string>
#include <gtkmm.h>
#include <giomm/resource.h>
#define GLEW_STATIC
#include <gl/glew.h>
class TestWindow : public Gtk::Window {
protected:
Gtk::GLArea mGlArea;
void onRealize() {
std::cout << "onRealize()" << std::endl;
mGlArea.make_current();
glewExperimental = true;
if (glewInit() != GLEW_OK) {
std::cout << "ERROR: Failed to initialize GLEW" << std::endl;
}
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
}
void onUnrealize() {
}
bool onRender(const Glib::RefPtr<Gdk::GLContext>& context) {
std::cout << "onRender()" << std::endl;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
mGlArea.queue_render();
mGlArea.queue_draw();
return true;
}
public:
TestWindow() {
set_title("Window Title");
set_child(mGlArea);
mGlArea.set_auto_render(true);
mGlArea.set_size_request(800, 600);
mGlArea.set_required_version(4, 0);
mGlArea.signal_realize().connect(sigc::mem_fun(*this, &TestWindow::onRealize));
mGlArea.signal_unrealize().connect(sigc::mem_fun(*this, &TestWindow::onUnrealize), false);
mGlArea.signal_render().connect(sigc::mem_fun(*this, &TestWindow::onRender), false);
mGlArea.show();
}
};
int main(int argc, char* argv[]) {
auto app = Gtk::Application::create("test.gtkmm");
return app->make_window_and_run<TestWindow>(argc, argv);
}

Related

SDL2 can't render PNG file as texture

I am trying to make a simple racing game with C++ using SDL2. When i tried rendering my car asset(PNG Image) it simply did not render saying in the console that it couldn't access the file. Note that the source files are located in an exclusive directory (src/), the headers are in /include and the images are located in /assets. Here is my code:
main.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <Headers/RenderWindow.hpp>
int main(int argc, char *args[])
{
if (SDL_Init(SDL_INIT_VIDEO) > 0)
{
std::cout << "SDL_Init has failed..." << std::endl;
}
if (!(IMG_Init(IMG_INIT_PNG)))
{
std::cout << "IMG_Init has failed" << std::endl;
}
RenderWindow window("Untitled Racing Game", 1280, 720);
SDL_Texture *blueCar = window.LoadTexture("../assets/blue_car.png");
bool run = true;
SDL_Event event;
while (run)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
run = false;
}
}
window.Clear();
window.Render(blueCar);
window.Display();
}
window.CleanUp();
SDL_Quit();
return 0;
}
RenderWindow.hpp
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
class RenderWindow
{
public:
RenderWindow(const char *title, int width, int height);
SDL_Texture *LoadTexture(const char *filePath);
void CleanUp();
void Clear();
void Render(SDL_Texture *texture);
void Display();
private:
SDL_Window *window;
SDL_Renderer *renderer;
};
RenderWindow.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "Headers/RenderWindow.hpp"
RenderWindow::RenderWindow(const char *title, int width, int height)
: window(NULL), renderer(NULL)
{
window = (SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN));
if (window == NULL)
{
std::cout << "Window Failed to Load. Error " << SDL_GetError() << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
}
SDL_Texture *RenderWindow::LoadTexture(const char *filePath)
{
SDL_Texture *texture = NULL;
texture = IMG_LoadTexture(renderer, filePath);
if (texture == NULL)
{
std::cout << "Failed to load texture, " << SDL_GetError() << std::endl;
}
return texture;
}
void RenderWindow::CleanUp()
{
SDL_DestroyWindow(window);
}
void RenderWindow::Clear()
{
SDL_RenderClear(renderer);
}
void RenderWindow::Render(SDL_Texture *texture)
{
SDL_RenderCopy(renderer, texture, NULL, NULL);
}
void RenderWindow::Display()
{
SDL_RenderPresent(renderer);
}

SDL2 cannot render entities from vector

Rendering individual textures was no problem at all, though after i wrapped these textures in an entity class, and put these in a vector, things just didn't work anymore (renders black screen). Anyone got a clue why?
main.cpp
#include "RenderWindow.hpp"
#include "vec.h"
#include "entity.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) > 0) {
std::cout << "Could not Init VIDEO, Error: " << SDL_GetError() << std::endl;
return 0;
}
if (!IMG_Init(IMG_INIT_PNG)) {
std::cout << "Could not Init IMG, Error: " << SDL_GetError() << std::endl;
return 0;
}
RenderWindow r("Bread.", 600, 600);
// entity vector
std::vector<Entity> entities = {Entity(Vec2i{5, 5}, r.CreateTexture("res/gfx/bob.png"))};
// single entity
Entity bob(Vec2i{5, 5}, r.CreateTexture("res/gfx/bob.png"));
bool running = true;
SDL_Event event;
while (running) {
Uint64 start = SDL_GetPerformanceCounter();
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
}
}
r.Clear();
// doesn't render (black screen)
for (const Entity& e : entities) {
r.RenderEntity(e);
}
// renders fine
r.RenderEntity(bob);
r.Display();
Uint64 end = SDL_GetPerformanceCounter();
float elapsedMS = (end - start) / (float)SDL_GetPerformanceFrequency() * 1000.0f;
SDL_Delay(floor(16.666f - elapsedMS));
}
return 0;
}
RenderWindow.cpp
#include "RenderWindow.hpp"
#include <iostream>
RenderWindow::RenderWindow(const char* p_title, int32_t p_w, int32_t p_h)
: window(NULL), renderer(NULL) {
this->window = SDL_CreateWindow(p_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_w, p_h, SDL_WINDOW_SHOWN);
if (this->window == NULL) {
std::cout << "Failed to initialize window, Error: " << SDL_GetError() << std::endl;
}
this->renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_ACCELERATED);
if (this->renderer == NULL) {
std::cout << "Failed to initialize renderer, Error: " << SDL_GetError() << std::endl;
}
}
RenderWindow::~RenderWindow() {
SDL_DestroyWindow(this->window);
SDL_DestroyRenderer(this->renderer);
SDL_Quit();
}
SDL_Texture* RenderWindow::CreateTexture(const char* p_path) {
return IMG_LoadTexture(this->renderer, p_path);
}
void RenderWindow::Clear() {
SDL_RenderClear(this->renderer);
}
void RenderWindow::RenderTexture(SDL_Texture* p_texture) {
SDL_RenderCopy(this->renderer, p_texture, NULL, NULL);
}
// **mentioned method**
// takes const Entity& and renders it's texture
void RenderWindow::RenderEntity(const Entity& p_entity) {
SDL_RenderCopy(this->renderer, p_entity.GetTexture(), NULL, NULL);
}
void RenderWindow::Display() {
SDL_RenderPresent(this->renderer);
}
and finally entity.cpp
#include "entity.h"
Entity::Entity(Vec2i p_pos, SDL_Texture* p_texture)
: pos(p_pos), texture(p_texture) {}
Entity::Entity()
: pos(Vec2i{0, 0}), texture(NULL) {}
Entity::~Entity() {
SDL_DestroyTexture(this->texture);
}
void Entity::SetPos(Vec2i p_pos) { this->pos = p_pos; }
const Vec2i& Entity::GetPos() const { return this->pos; }
void Entity::SetTexture(SDL_Texture* p_texture) { this->texture = p_texture; }
// used to get texture of entity to pass to renderer
SDL_Texture* Entity::GetTexture() const { return this->texture; }
void Entity::Move(Vec2i p_pos) {
this->pos = p_pos;
}
void Entity::Move(size_t p_x, size_t p_y) {
this->pos.x += p_x;
this->pos.y += p_y;
}
The creation of entities requires a temporary Entity, which is destroyed afterwards. Since you did not implement a copy constructor, this leaves the new Entity with a dangling pointer to a freed object.
The quickest fix is to change the type of Entity::texture to std::shared_ptr<SDL_Texture>.
Alternatively, you can create a move constructor and prevent copy constructors:
Entity::Entity(const Entity&) = delete;
Entity::Entity(Entity&& other)
: pos(other.pos), texture(nullptr) {
std::swap(texture, other.texture);
}

std::cout << glGetString(GL_RENDER) << std::endl; Throws an Error but not GL_Renderer or GL_Verision and I can't figure out why?

First time asking a question on here so if it's not layed out correctly or something is missing I'll try to get everything else up.
I'm trying to learn OpenGl because I'm interested in developing games of my own and I would rather create my own engine than one already out there.
I'm using GLEW also and I know it inits because the code doesn't output an Error
I spend alittle while googling the error code and the OpenGL but none of the problems really match what I'm getting.
I also tried the GLEW_Experimental = true but that did not change anything.
Code: main
#include "src/graphics/window.h"
int main()
{
using namespace FutureGamingEngine;
using namespace graphics;
Window window("Test", 1080, 720);
glClearColor(0, 255, 0, 1.0f); //Red, Green, Blue, No Idea
std::cout << glGetString(GL_VERSION) << std::endl;
std::cout << glGetString(GL_RENDERER) << std::endl;
std::cout << glGetString(GL_RENDER) << std::endl;
while (!window.closed())
{
window.clear();
glBegin(GL_QUADS);
glVertex2f(-0.5f, -0.5f);
glVertex2f(-0.5f, 0.5f);
glVertex2f(0.5f, 0.5f);
glVertex2f(0.5f,-0.5f);
glEnd();
window.update();
}
//system("PAUSE");
return 0;
}
Window:
#include "window.h"
namespace FutureGamingEngine
{
namespace graphics
{
void windowResize(GLFWwindow *window, int width, int height);
Window::Window(const char *title, int width, int height)
{
c_title = title;
c_height = height;
c_width = width;
if (!init())
{
glfwTerminate();
}
}
Window::~Window()
{
glfwTerminate();
}
bool Window::init()
{
glewExperimental = true;
if (!glfwInit())
{
std::cout << "Error Code: 0" << std::endl;
return false;
}
//Create a windowed mode and it's OpenGl Content
c_window = glfwCreateWindow(c_width, c_height, c_title, NULL, NULL);
//If we fail to make the window Terminate OpenGL
if (!c_window)
{
glfwTerminate();
return false;
}
//std::cout << "Open GL: " << glGetString(GL_VERSION) << std::endl;
glfwMakeContextCurrent(c_window);
glfwSetWindowSizeCallback(c_window, windowResize);
if (glewInit() != GLEW_OK)
{
std::cout << "Error Code: 1" << std::endl;
return false;
}
return true;
}
bool Window::closed() const
{
return glfwWindowShouldClose(c_window);
}
void Window::update()
{
//poll for and process events
glfwPollEvents();
glfwGetFramebufferSize(c_window, &c_width, &c_height);
//swap front and backbuffers
glfwSwapBuffers(c_window);
}
void Window::clear() const
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void windowResize(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
}
}
The Header for window:
#pragma once
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
namespace FutureGamingEngine
{
namespace graphics
{
class Window
{
private:
const char *c_title;
int c_width, c_height;
GLFWwindow *c_window;
bool c_closed;
public:
Window(const char *a_name, int a_width, int a_height);
~Window();
bool closed() const;
void update();
void clear() const;
inline int getHeight() const { return c_height; };
inline int getWidth() const { return c_width; };
private:
bool init();
};
}
}
I'm expecting it to tell me the Render Version. What I'm actually getting is Error Produced on std::cout << glGetString(GL_RENDER) << std::endl; :
Exception thrown at 0x7C50F6E0 (ucrtbased.dll) in FutureGamingEngine-Core.exe: 0xC0000005: Access violation reading location 0x00000000.
(https://i.imgur.com/uKu3hxX.png)
and the doesn't get to rendering the Triangle like it did prior to me asking for Gl_render
GL_RENDERER is valid enum, GL_RENDER is not. See OpenGL doc
Thank you Ripi2! I apperently did not look hard enough :D

GLEW _First was nullptr

So I have been working on a game through C++ with GLFW and GLEW and everything was going fine until I implemented GLEW then I get an error that I have never encountered before and I don't have the foggiest on what to do, I have googled it and done some research but to no avail. I have noticed that in the stack frame section it says something to do with this line of code in my main.cpp
std::cout << glGetString(GL_VERSION) << std::endl;
Also it says something to do with memory. I'll leave the rest of my code down below and if there's any info you need just ask and I will try my best to provide it
So I just discovered if i take out
std::cout << glGetString(GL_VERSION) << std::endl;
then it works however the window isn't created.
Where do I go from here?
Any idea?
#include "src\graphics\window.h"
int main() {
using namespace benji;
using namespace graphics;
Window window("Benji Engine", 1280, 720);
glClearColor(0.2f, 0.3f, 0.8f, 1.0f);
std::cout << glGetString(GL_VERSION) << std::endl;``
while (!window.closed()) {
std::cout << window.getWidth() << ", " << window.getHeight() << std::endl;
window.clear();
glBegin(GL_TRIANGLES);
glVertex2f(-0.5f, -0.5f);
glVertex2f(0.0f, 0.5f);
glVertex2f(0.5f, -0.5f);
glEnd();
window.update();
}
return 0;
}
main.h
#pragma once
class main
{
public:
main();
~main();
};
window.cpp
#include "window.h"
namespace benji { namespace graphics {
void windowResize(GLFWwindow *window, int width, int height);
Window::Window(const char *title, int width, int height) {
m_Title = title;
m_Width = width;
m_Height = height;
if (!init()) {
glfwTerminate();
}
}
Window::~Window() {
glfwTerminate();
}
bool Window::init() {
if (!glfwInit()) {
std::cout << "Failed to initialize GLFW!" << std::endl;
return false;
}
m_Window = glfwCreateWindow(m_Width, m_Height, m_Title, NULL, NULL);
if (!m_Window) {
std::cout << "Failed to create GLFW window!" << std::endl;
return false;
}
glfwMakeContextCurrent(m_Window);
glfwSetWindowSizeCallback(m_Window, windowResize);
if (glewInit != GLEW_OK) {
std::cout << "GLEW FAILED!" << std::endl;
return false;
}
return true;
}
void Window::clear() const {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Window::update(){
glfwPollEvents();
glfwSwapBuffers(m_Window);
}
bool Window::closed() const {
return glfwWindowShouldClose(m_Window) == 1;
}
void windowResize(GLFWwindow *window, int width, int height) {
glViewport(0, 0, width, height);
}
}}
window.h
#pragma once
#include <iostream>
#include <GL\glew.h>
#include <GLFW\glfw3.h>
namespace benji {
namespace graphics {
class Window {
private:
const char *m_Title;
int m_Width, m_Height;
GLFWwindow *m_Window;
bool m_Closed;
public:
Window(const char *title, int width, int height);
~Window();
bool closed() const;
void update();
void clear() const;
int getWidth() const {
return m_Width;
}
int getHeight() const { return m_Height; }
private:
bool init();
};
}
}
In Window.cpp:
if (glewInit != GLEW_OK) {
std::cout << "GLEW FAILED!" << std::endl;
return false;
}
glewInit() is a function, not a variable. You need to call it as a function. I'm surprised this even compiled.
All other OpenGL functions that come from after version 1.1 will throw errors to the effect of ACCESS_VIOLATION READING ADDRESS 0x00000000 or some similar error, because if glewInit() is not properly called, none of the function macros provided by GLEW will point to valid function pointers.

SDL not responding after running for a few seconds on linux

I was following the SDL Game development book and I cant even get the first file to work right. Upon the application starting it renders the window and then after a few seconds Linux says the game is not responding and ask me to force quit. This repeats every few seconds if I click wait. One thing I have noticed is that SDL_PollEvent never returns true.I am not sure why things are not working. Here is my code.
Main.cpp
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include "Game.h"
// our Game object
Game* g_game = 0;
int main(int argc, char* argv[]) {
g_game = new Game();
g_game->init("Chapter 1", 100, 100, 640, 480, 0);
while(g_game->running()) {
g_game->handleEvents();
//g_game->update();
g_game->render();
}
g_game->clean();
return 0;
}
Game.h
#ifndef __Game__
#define __Game__
#if !WINDOWS
#include <SDL2/SDL.h>
#else
#include <SDL.h>
#endif
class Game {
public:
Game() {}
~Game() {}
// simply set the running variable to true
bool init(const char* title, int xpos, int ypos, int width, int
height, bool fullscreen);
void render();
void update();
void handleEvents();
void clean();
// a function to access the private running variable
bool running() {
return m_bRunning;
}
private:
SDL_Window* m_pWindow;
SDL_Renderer* m_pRenderer;
bool m_bRunning;
};
#endif /* defined(__Game__) */
Game.cpp
#include "Game.h"
#include <iostream>
bool Game::init(const char* title, int xpos, int ypos, int width,
int height, bool fullscreen) {
// attempt to initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) == 0) {
std::cout << "SDL init success\n";
// init the window
int flags = 0;
if(fullscreen) {
flags = SDL_WINDOW_FULLSCREEN;
}
m_pWindow = SDL_CreateWindow(title, xpos, ypos,
width, height, flags);
if(m_pWindow != 0) { // window init success
std::cout << "window creation success\n";
m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);
if(m_pRenderer != 0) { // renderer init success
std::cout << "renderer creation success\n";
SDL_SetRenderDrawColor(m_pRenderer,
255,0,255,255);
} else {
std::cout << "renderer init fail\n";
return false; // renderer init fail
}
} else {
std::cout << "window init fail\n";
return false; // window init fail
}
} else {
std::cout << "SDL init fail\n";
return false; // SDL init fail
}
std::cout << "init success\n";
m_bRunning = true; // everything inited successfully, start the main loop
return true;
}
void Game::render() {
SDL_RenderClear(m_pRenderer); // clear the renderer to the draw color
SDL_RenderPresent(m_pRenderer); // draw to the screen
}
void Game::clean() {
std::cout << "cleaning game\n";
SDL_DestroyWindow(m_pWindow);
SDL_DestroyRenderer(m_pRenderer);
SDL_Quit();
}
void Game::handleEvents() {
SDL_Event event;
while(SDL_PollEvent(&event)) {
std::cout << "Checking Events";
switch(event.type) {
case SDL_QUIT:
std::cout << "Quiting";
m_bRunning = false;
break;
default:
break;
}
}
}
Edit:
so I made a minamal version of the code and now i get a new error. The error says "Segmentation Fault (core dumped)". Based on running it to a specific line in debug the error seems to appear at the line that says "SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp);" I am not sure what the error is though
Here is the minial code:
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <iostream>
#include <SDL2/SDL.h>
int main(int argc, char** argv) {
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window *win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
if(win == NULL) {
std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if(ren == NULL) {
SDL_DestroyWindow(win);
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
std::string imagePath = "cb.bmp";
SDL_Surface *bmp = SDL_LoadBMP(imagePath.c_str());
if(bmp == NULL) {
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
std::cout << "SDL_LoadBMP Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp);
if(tex == NULL) {
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
std::cout << "SDL_CreateTextureFromSurface Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_FreeSurface(bmp);
SDL_Event e;
bool quit = false;
while(!quit) {
while(SDL_PollEvent(&e)) {
//If user closes the window
if(e.type == SDL_QUIT) {
quit = true;
}
//If user presses any key
if(e.type == SDL_KEYDOWN) {
quit = true;
}
//If user clicks the mouse
if(e.type == SDL_MOUSEBUTTONDOWN) {
quit = true;
}
}
SDL_RenderClear(ren);
SDL_RenderPresent(ren);
}
SDL_DestroyTexture(tex);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
I have compiled and run your minimal code successfully under Linux with SDL 2.0.4. I used a simple image as "cb.bmp".
Try the following :
compile like this : g++ -Wall -ggdb $(sdl2-config --cflags) -o program main.cpp -lSDL2
gdb ./program, then type 'run'
when it crashes, type 'bt' (for backtrace)
copy the output here
My guess is : either the "bmp" file format is not supported or the rendering driver is not supported. try to use :
SDL_CreateRenderer(win, -1, 0);