So I'm trying to write text to an SDL_Window but I can't get the text to show up. And i've tried messing around with different colors and all of that stuff.
Here's my code
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include <GL/glew.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_VIDEO) == (-1))
{
printf("Could not initialize SDL: %s.\n", SDL_GetError());
exit(-1);
}
int WINWIDTH = 640;
int WINHEIGHT = 480;
SDL_Window* window = SDL_CreateWindow("Text Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINWIDTH, WINHEIGHT, SDL_WINDOW_OPENGL);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
TTF_Font* Sans = TTF_OpenFont("Fonts\\arial.ttf", 24);
SDL_Color White = { 255, 0, 0 };
SDL_Surface* surfaceMessage = TTF_RenderText_Solid(Sans, "put your text here", White);
SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, surfaceMessage);
SDL_Rect Message_rect;
Message_rect.x = 0;
Message_rect.y = 0;
Message_rect.w = 100;
Message_rect.h = 100;
SDL_RenderCopy(renderer, Message, NULL, &Message_rect);
system("pause");
exit(0);
}
I have tried multiple ways of creating text but none of it works.
Related
I've been trying to load 2 images in a SDL window, like a player and an enemy, but SDL2_image loads only one image at a time
here's my code :
#include<iostream>
#define SDL_MAIN_HANDLED
#include<SDL2/SDL.h>
#include<SDL2/SDL_image.h>
using namespace std;
SDL_Texture* load(SDL_Renderer* ren, const char* path, SDL_Rect rect)
{
SDL_Texture* img = IMG_LoadTexture(ren, path);
if (img == NULL)
cout << SDL_GetError() << endl;
SDL_RenderClear(ren);
SDL_RenderCopy(ren, img, NULL, &rect);
SDL_RenderPresent(ren);
return img;
}
int main()
{
SDL_Init(SDL_INIT_EVERYTHING);
IMG_Init(IMG_INIT_PNG);
SDL_Window* window = SDL_CreateWindow("SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 460, 380, SDL_WINDOW_RESIZABLE);
SDL_Surface* icon = IMG_Load("sdl.png");
SDL_SetWindowIcon(window, icon);
SDL_Renderer* ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Rect rect,r2;
rect.x = 0; r2.x = 65;
rect.y = 0; r2.y = 80;
rect.w = 64; r2.w = 64;
rect.h = 64; r2.h = 64;
SDL_Texture* img = load(ren, "player.png", rect);
SDL_Delay(2000);
SDL_Texture* tex = load(ren, "enemy.png", r2);
SDL_Event events; bool running = true;
while (running == true)
{
if (SDL_PollEvent(&events))
{
if (events.type == SDL_QUIT)
{
running = false;
break;
}
}
}
IMG_Quit();
SDL_Quit();
return 0;
}
I used SDL_Delay to demonstrate what happens
it loads "player.png" first and then after 2 seconds, it loads "enemy.png"
I wanted to load both at the same time but I couldn't
Please help!
solved, it was due to SDL_RenderClear
I am trying to display a menu using the Menu class. But in the function draw() of that class, the SDL_BlitSurface is not working and is throwing a segmentation default while executing this line :
SDL_BlitSurface(el.surfaceNormal, NULL, surface, &el.rect);
Here is the code of the function:
void Menu::draw(SDL_Surface* surface) {
for(int i=0; i<menuElementList.size(); i++){
auto el = menuElementList.at(i);
SDL_BlitSurface(el.surfaceNormal, NULL, surface, &el.rect);
}
}
The struct I am using in vector:
struct menuElement{
SDL_Surface* surfaceNormal;
SDL_Surface* surfaceHover;
SDL_Rect rect;
std::string text;
};
Normally, I should be able to render all of the surface present in the vector, but for a reason I can't figure, it is not working.
The code to populate the vector:
void Menu::addMenu(std::string name, int x, int y) {
menuElement m;
TTF_Font* Sans = TTF_OpenFont("OpenSans-Light.ttf", 25);
if(!Sans){
std::cout << TTF_GetError() << std::endl;
}
SDL_Color White = {255, 255, 255};
SDL_Surface* surfaceMessage = TTF_RenderText_Solid(Sans, name.c_str(), White);
m.surfaceNormal = surfaceMessage;
SDL_Color Red = {255, 0, 0};
SDL_Surface* hoverMessage = TTF_RenderText_Solid(Sans, name.c_str(), Red);
m.surfaceHover = hoverMessage;
SDL_Rect rect;
rect.x = rect.y = 50;
m.rect = rect;
m.text = name;
SDL_FreeSurface(surfaceMessage);
SDL_FreeSurface(hoverMessage);
menuElementList.push_back(m);
}
I know that the vector gets populated because I can display the text attribute of each element in it. What's wrong?
Well the error is pretty simple you would have realized if had debugged a bit, here is a MVCE that you SHOULD have done.
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <iostream>
#include <vector>
#include <string>
#define HEIGHT 600
#define WIDTH 800
using namespace std;
struct menuElement{
SDL_Surface* surfaceNormal;
SDL_Surface* surfaceHover;
SDL_Rect rect;
std::string text;
};
std::vector<menuElement> menuElementList;
void add_element(std::string name, int x, int y) {
menuElement m;
TTF_Font* Sans = TTF_OpenFont("OpenSans-Light.ttf", 25);
if(!Sans){
std::cout << TTF_GetError() << std::endl;
}
SDL_Color White = {255, 255, 255};
SDL_Surface* surfaceMessage = TTF_RenderText_Solid(Sans, name.c_str(), White);
m.surfaceNormal = surfaceMessage;
SDL_Color Red = {255, 0, 0};
SDL_Surface* hoverMessage = TTF_RenderText_Solid(Sans, name.c_str(), Red);
m.surfaceHover = hoverMessage;
SDL_Rect rect{x, y, 50, 50}; // You were never using x and y before now it draws at that position with a rect of size 50x50
m.rect = rect;
m.text = name;
// SDL_FreeSurface(surfaceMessage); << how is this not crashing in your system when blitting, I don't know
// SDL_FreeSurface(hoverMessage);
menuElementList.push_back(m);
}
int main() {
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
SDL_Window *window = SDL_CreateWindow("TextFail", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
SDL_Surface *surface = SDL_GetWindowSurface(window);
bool quit = false;
SDL_Event event;
add_element("ello", 20, 20);
add_element("Bye", 40, 40);
while (!quit) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
for (auto &el : menuElementList)
SDL_BlitSurface(el.surfaceNormal, NULL, surface, &el.rect);
SDL_UpdateWindowSurface(window);
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I commented the 2 lines that are messing with you, even if the vector gets populated its getting populated with uninitialized data since you FREE the surfaces, you should do that when freeing the menuElement (If you're using C++ in the menuElement destructor for example or on a free_menu_element(menuElement *e) { .. } function if C)
Remember when you copy pointers you copy the direction of memory they point to and not its contents.
You were also never using x and y!
so I was following this tutorial, and everything was going all smooth and dandy, until I encountered a problem, namely that I couldn't load a .bmp.
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include <iostream>
#include <SDL2/SDL_main.h>
using namespace std;
int main(int argc, char* argv[]) {
bool quit = false;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window;
window = SDL_CreateWindow("window", 100, 100, 1280, 720, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if(window == NULL){
cout << "Disn't work, here is why: " << SDL_GetError()<< endl;
return 0;
}
SDL_Renderer* renderer = NULL;
renderer= SDL_CreateRenderer(window, -1 ,SDL_RENDERER_ACCELERATED);
SDL_Event* mainEvent = new SDL_Event();
SDL_Texture* grass_image = NULL;
grass_image = IMG_LoadTexture(renderer, "grass.bmp");
SDL_Rect grass_rect;
grass_rect.x = 10;
grass_rect.y = 50;
grass_rect.w = 250;
grass_rect.h = 250;
while(!quit && mainEvent->type != SDL_QUIT){
SDL_PollEvent(mainEvent);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, grass_image, NULL, &grass_rect);
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
delete mainEvent;
return 0;
}
When I try to compile the code (in Code::Blocks) it gives me the error of
Undefined reference to "IMG_LoadTexture"
Well, I tried to change IMG_LoadTexture(renderer, "grass.bmp"); to IMG_LoadTexture(renderer, "/the/full/path/of/grass.bmp");but this didn't work either. Same error. Have I written something wrong, or missed some part? Also, grass.bmp is in the same folder as main.cpp (the code above).
The error here says that you have declared a function but have not defined it - undefined reference.
Most probably it happened because you forgot to link against library SDL_image to which function IMG_LoadTexture belongs.
Today I started a C++/SDL2 Snake clone, and I've been looking for ways to make my code neater, -particularly with classes. I tried to put all the SDL code used for the window/display in a class. When I run the code, the window closes instantly. From the error tests I set up in display.cpp, it also tells me through the console that SDL_UpdateWindowSurface() (in display.update()) is always returning -1. Why does this happen when I rearrange my code like this?
With this code I load an image in main() and display it through my class' function applySurface(). The idea is to have classes/objects for the game's grid/board, the snake, etc., -each calling applySurface() for their own images. Feel free to tell me if this is a bad idea altogether.
main.cpp:
#include <SDL.h>
#include "display.h"
SDL_Event event;
SDL_Surface* image = nullptr;
int main(int argc, char* args[])
{
Display display;
display.loadImage("image.bmp");
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
return false;
bool quit = false;
while (!quit)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = true;
}
display.applySurface(0, 0, image, display.windowSurface);
display.update();
}
SDL_FreeSurface(image);
SDL_Quit();
return 0;
}
display.h:
#pragma once
#include <SDL.h>
#include <string>
#include <iostream>
class Display
{
public:
SDL_Window* window;
SDL_Surface* windowSurface;
Display();
SDL_Surface *loadImage(std::string fileName);
void applySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip = nullptr);
void update();
~Display();
private:
const int WINDOW_WIDTH = 612;
const int WINDOW_HEIGHT = 632;
const int SCREEN_BPP = 2;
};
display.cpp:
#pragma once
#include "display.h"
Display::Display()
{
window = SDL_CreateWindow("Snake", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
if (window == NULL)
std::cout << "Error: SDL_CreateWindow failed." << std::endl;
windowSurface = SDL_GetWindowSurface(window);
}
SDL_Surface* Display::loadImage(std::string fileName)
{
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimizedImage = NULL;
loadedImage = SDL_LoadBMP(fileName.c_str());
if (loadedImage != NULL)
{
optimizedImage = SDL_ConvertSurface(loadedImage, windowSurface->format, 0);
SDL_FreeSurface(loadedImage);
if (optimizedImage != NULL)
SDL_SetColorKey(optimizedImage, SDL_TRUE, SDL_MapRGB(optimizedImage->format, 255, 255, 255));
}
return optimizedImage;
}
void Display::applySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface(source, clip, destination, &offset);
}
void Display::update()
{
if (SDL_UpdateWindowSurface(window) == -1)
std::cout << "Error: SDL_UpdateWindowSurface() failed." << std::endl;
}
Display::~Display()
{
SDL_FreeSurface(windowSurface);
windowSurface = NULL;
SDL_DestroyWindow(window);
window = NULL;
}
This is a valid use of classes to structure your code. SDL_Init needs to come before any other SDL functions, which means you're best off moving SDL_Init to the top of main or adding it to the display constructor. If you add it to the beginning of the display constructor this means that you can only have one display class object running at a time, which would likely be fine in this case.
When I run this it just shows a black screen, and if i Put SDL_GetError() at the end it prints a blank line.....
Any ideas on how to fix this?
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
class character {
public: SDL_Rect src, cur;
public: SDL_Texture *image;
void setSrc(int x, int y, int w, int h) {
src.x = x;
src.y = y;
src.w = w;
src.h = h;
}
void setCur(int x, int y, int w, int h) {
src.x = x;
src.y = y;
src.w = w;
src.h = h;
}
};
int main(int argc, char* argv[]) {
bool in = true;
character p1, p2, ball;
SDL_Window *window = 0;
SDL_Renderer *renderer = 0;
SDL_Surface *screen, *imageLoader;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Pong",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, 0);
p1.setSrc(0, 0, 100, 500);
p1.setCur(0, 0, 100, 500);
imageLoader = IMG_Load("/home/donaldo/Documents/Games/Images/player.bmp");
p1.image = SDL_CreateTextureFromSurface(renderer, imageLoader);
SDL_RenderCopy(renderer, p1.image, &p1.src, &p1.cur);
SDL_RenderPresent(renderer);
SDL_Delay(3000);
return 0;
}
You have a typo in your setCur() function. I assume you want to be setting the cur rectangle, not src again.
Also, not related but it's good practice to free the surface and texture you allocated when you're done with them.