I am working on a simple game in C++, with SDL as my API. I put my image bliting functions in a class on a separate document so that it would less messy on my main file. However, when I try to call the functions using the object for the class, my IDE says that I am making an undefined reference to the functions. Here is the main file:
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include "imageBlitingFunctions.h"
#include <iostream>
#include <string>
#include <sstream>
int screenW = 640;
int screenH = 480;
int screenBPP = 32;
SDL_Surface* window = SDL_SetVideoMode(screenW, screenH, screenBPP, SDL_SWSURFACE);
imageBlitingFunctions IBFobject;
SDL_Surface* background1;
SDL_Surface* player1;
int main(int argc, char* args[])
{
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
background1 = IBFobject.loadIMG("background.png");
player1 = IBFobject.loadIMG("swordtest.png");
IBFobject.blitIMG(0, 0, window, background1, 0, 0, 1000, 1000);
IBFobject.blitIMG(0, 0, window, player1, 100, 0, 100, 300);
SDL_FreeSurface(background1);
SDL_FreeSurface(player1);
SDL_Quit();
return 0;
}
Here is the header for the class:
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include <iostream>
#include <string>
#ifndef IMAGEBLITINGFUNCTIONS_H
#define IMAGEBLITINGFUNCTIONS_H
class imageBlitingFunctions
{
public:
SDL_Surface *loadIMG(std::string filename);
void blitIMG(int pX, int pY, SDL_Surface *window, SDL_Surface *image, int cpX, int cpY, int cpH, int cpW);
SDL_Surface *loadText(int red, int blue, int green, std::string fontname, int fontSize, std::string text);
};
#endif // IMAGEBLITINGFUNCTIONS_H
And here is the class:
#include "imageBlitingFunctions.h"
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include <iostream>
#include <string>
SDL_Surface* imageBlitingFunctions::loadIMG(std::string filename)
{
SDL_Surface *img = IMG_Load(filename.c_str());
SDL_Surface *imgOPT = SDL_DisplayFormat(img);
SDL_FreeSurface(img);
return imgOPT;
}
void imageBlitingFunctions::blitIMG(int pX, int pY, SDL_Surface *window, SDL_Surface *image, int cpX, int cpY, int cpH, int cpW)
{
SDL_Rect positionIMG;
positionIMG.x = pX;
positionIMG.y = pY;
SDL_Rect clipP;
clipP.x = cpX;
clipP.y = cpY;
clipP.h = cpH;
clipP.w = cpW;
SDL_BlitSurface(image, &clipP, window, &positionIMG);
SDL_Flip(window);
}
SDL_Surface* imageBlitingFunctions::loadText(int red, int blue, int green, std::string fontname, int fontSize, std::string text)
{
int color1 = red;
int color2 = blue;
int color3 = green;
SDL_Color textColor = {color1, color2, color3};
TTF_Font *font1 = TTF_OpenFont(fontname.c_str(), fontSize);
SDL_Surface *message1 = TTF_RenderText_Solid(font1, text.c_str(), textColor);
return message1;
}
Any help would be appreciated.
An undefined reference to a function means that the linker can't find the function definition. The definition of the function is what you've put in the code "And here is the class:" (maybe you call it imageBlitingFunctions.cpp or something similar?) so the problem is that you're IDE can't find this file.
To solve this problem you need to fix the project configuration.
Related
Could anyone break the MyWindow class out into separate MyWindow.h and MyWindow.cpp files from this excellent FLTK example?
I have tried all afternoon. I am stuck on the (void*)this part in the Fl::add_timeout method. I am sure I have other things wrong as well.
I would like to see how the recursion is best handled. Do you MyWindow::RenderImage_CB or leave it as RenderImage_CB?
Adding the code here for convenience.
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// Demonstrate how to display a pixel buffer in FLTK
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
static void RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, RenderImage_CB, userdata);
}
public:
// CTOR
MyWindow(int w, int h, const char *name=0) : Fl_Double_Window(w,h,name) {
end();
RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, RenderImage_CB, (void*)this);
}
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}
};
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
Separated this way gives a compiler error:
main.cpp
#include "MyWindow.h"
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
MyWindow.h
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw();
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
void RenderImage_CB(void *userdata);
public:
// CTOR
MyWindow(int w, int h, const char *name=0) : Fl_Double_Window(w,h,name){};
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b);
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage();
};
MyWindow.cpp
#include "MyWindow.h"
void MyWindow::draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
void MyWindow::RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
}
MyWindow::MyWindow(int w, int h, const char *name) : Fl_Double_Window(w,h,name) {
end();
MyWindow::RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, (void*)this);
}
void MyWindow::PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
void MyWindow::RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}
Using the above my first error is:
MyWindow.cpp:10:71: error: no matching function for call to 'Fl::repeat_timeout(double, <unresolved overloaded function type>, void*&)'
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
This compiles and runs:
main.cpp
#include "MyWindow.h"
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
MyWindow.h
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw();
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
static void RenderImage_CB(void *userdata);
public:
// CTOR
MyWindow(int w, int h, const char *name=0);// : Fl_Double_Window(w,h,name){};
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b);
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage();
};
MyWindow.cpp
#include "MyWindow.h"
MyWindow::MyWindow(int w, int h, const char *name) : Fl_Double_Window(w,h,name) {
end();
MyWindow::RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, (void*)this);
}
void MyWindow::draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
void MyWindow::RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
}
void MyWindow::PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
void MyWindow::RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}
I'm trying to render a SDL_Rect in a class, I send the renderer to the "draw" function of my class, and then render it from there.
void Tray::draw(SDL_Renderer *renderer){
SDL_RenderFillRect(renderer, &bckRect);
}
When I put the same code on my main loop. All goes fine, but when I do this from my tray class, It compiles, but doesn't run.
Simplified code:
main.cpp
#include <iostream>
#include <SDL2/SDL.h>
// local includes
#include "editor.h"
using namespace std;
int main(int argc, const char * argv[]) {
Editor *editor = new Editor();
while (editor->running){
editor->render();
}
editor->clean();
return 0;
}
editor.h
#ifndef EDITOR_H
#define EDITOR_H
#include <iostream>
#include <SDL2/SDL.h>
#include "Gui-classes/tray.h"
#include "properties.h"
class Editor{
private:
// Window variables
SDL_Window *window;
SDL_Renderer *renderer;
Tray *tray;
public:
Editor();
~Editor();
void render();
};
#endif
editor.cpp
#include "editor.h"
Editor::Editor(){
props = new Properties();
if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {
window = SDL_CreateWindow("Great Editor", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1000, 600, SDL_WINDOW_RESIZABLE);
running = true;
if (window) {
std::cout << "Window created!" << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, 0);
}
}
void Editor::render(){
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 12, 12, 55, 255);
tray->draw(renderer);
SDL_RenderPresent(renderer);
}
void Editor::clean(){
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
std::cout << "Window ended" << std::endl;
}
tray.h
#ifndef TRAY_H
#define TRAY_H
#include <iostream>
#include <SDL2/SDL.h>
class Tray{
private:
// Position variables
int x;
int y;
int w;
int h;
//Display variables
SDL_Color color;
SDL_Rect bckRect;
public:
Tray();
~Tray();
void draw(SDL_Renderer *renderer);
};
#endif
Tray.cpp
#include "tray.h"
Tray::Tray(){
bckRect.x = x;
bckRect.x = y;
bckRect.w = w;
bckRect.h = h;
}
Tray::~Tray(){
}
void Tray::draw(SDL_Renderer *renderer){
SDL_RenderFillRect(renderer, &bckRect);
//std::cout << "teeest" << std::endl;
}
Thanks for the help.
I am currently learning SDL2 and just managed to create a ping pong game. Some friends told me that I should start using classes for managing as an example player1 and player2. I know how to create a class but I do not understand how I would be able to pass SDL_Renderer between classes in order to render an object from within the class to the main.cpp file.
#include "SDL2/SDL.h"
#include "SDL2/SDL_render.h"
#include <iostream>
#include <windows.h>
#include <thread>
#include "player.h"
Player Player; //defining the class
const int WINDOW_WIDTH = 1280;
const int WINDOW_HEIGHT = 720;
int main(int argc, char *args[]) {
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window;
SDL_Renderer *renderer;
window = SDL_CreateWindow ("Test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH,
WINDOW_HEIGHT,
0
);
if (window == NULL) {
std::cout << "Window could not load" << SDL_GetError() << std::endl;
return 0;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
while (running) //running is a bool (true) {
Player.draw();
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
What do I have to do in my player.cpp draw function in order to draw an object on the screen?
Using C++ windows, compiling the code with g++ main.cpp player.cpp -o main.exe -IC:\MinGW\i686-w64-mingw32\include -LC:\MinGW\i686-w64-mingw32\lib -lmingw32 -lSDL2main -lSDL2
In main.cpp
Player.draw(renderer)
(presuming you are using the same code as above, just pass "renderer" to the Player.draw() function.)
In player.h
class Player {
public:
void draw(SDL_Renderer *renderer)
};
In player.cpp
void Player::draw(SDL_Renderer *renderer) {
SDL_Rect object;
object.x = 0;
object.y = 0;
object.h = 10;
object.w = 10;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &object);
SDL_RenderFillRect(renderer, &object);
}
// will draw a white box with at position (0,0)
I believe this is a simple way to do it
So I recently downloaded the SDL_2 libraries and all the components and wanted to create a simple GUI/UI that had a "button" with a picture in it. I've looked up a few guides and I've copied and rewritten a lot of code as well. But the latest code sample that I found that worked was in C which contained no classes and was pretty messy. So I rewrote it into C++ but for some reason, it does not want to load the image.
I've purposely not posted any Destructor or any functions that I'm 99% sure was not causing the issue. To the post, to not make it too long, I believe the error is in the const void clear function, but I'm not sure.
Any ideas on why? Been trying to figure this out for a long time now, thank you for any advise / Help :)
Window.h:
#pragma once
#include <SDL.h>
class Window
{
public:
Window(const char* title, int width, int height);
~Window();
void getEvents();
const void clear();
inline const bool isClosed() { return _closed; }
private:
const char* _title = "SDL_6";
int _width = 480;
int _height = 720;
bool _closed = false;
bool init();
SDL_Window *_window = nullptr;
SDL_Renderer *_renderer = nullptr;
SDL_Surface *_surface = nullptr;
};
Window.cpp:
#include "Window.h"
#include <iostream>
#include <SDL_image.h>
#define IMG_PATH "D:\\Picture\\Bowser\\star.jpg"
Window::Window(const char *title, int width, int height) :
_title(title), _width(width), _height(height)
{
_closed = !init();
}
const void Window::clear()
{
int w = 120;
int h = 120;
SDL_Texture *img = NULL;
SDL_Rect texr;
texr.x = 120;
texr.y = 120;
texr.h = 120;
texr.w = 120;
const char* file = "D:\\Pictures\\bowser\\star.jpg";
SDL_Surface *IMG_Load(const char* file);
SDL_RenderClear(_renderer);
SDL_RenderCopy(_renderer, img, NULL, &texr);
img = IMG_LoadTexture(_renderer, IMG_PATH);
SDL_QueryTexture(img, NULL, NULL, &w, &h);
SDL_RenderPresent(_renderer);
}
main.cpp
#include "Window.h"
int main(int argc, char* argv[])
{
Window window("SDL_6", 720, 480);
while (!window.isClosed())
{
window.getEvents();
window.clear();
}
return 0;
}
So the answer was to not declare the:
SDL_Surface IMG_Load(const char file); but to call it instead, also changed the order of the code in the: const void Window::clear() function. Thank you for the answer O'Neil :-)
So I'm debugging some horrible code I slung together and finally widdled my way down to (hopefully) the last error in my scene_manager.cpp but I don't seem to understand why I'm getting it.
Error
|22|undefined reference to `scene_manager::applySurface(int, int, SDL_Surface*, SDL_Surface*)'|
scene_manager.cpp
#include "scene_manager.h"
scene_manager::scene_manager(screen_manager* s){
screen = s;
}
void scene_manager::add_object(object_manager* obj){
if(game_objects.find(obj->get_name()) != game_objects.end()){
game_objects[obj->get_name()] = obj;
}
}
void applySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination){
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface(source, NULL, destination, &offset);
}
int scene_manager::render(){
for(iter = game_objects.begin(); iter != game_objects.end();iter++){
applySurface(game_objects.at(iter->first)->get_x(),game_objects.at(iter->first)->get_y(),game_objects.at(iter->first)->get_sprite(),screen->get_screen());
}
if(SDL_Flip(screen->get_screen()) == -1){
return 1;
}
return 0;
}
scene_manager.h
#ifndef SCENE_MANAGER_H
#define SCENE_MANAGER_H
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "object_manager.h"
#include "screen_manager.h"
#include <map>
#include <string>
class scene_manager{
public:
scene_manager();
scene_manager(screen_manager* s);
void add_object(object_manager* obj);
int render();
private:
std::map<std::string,object_manager*>game_objects;
std::map<std::string,object_manager*>::iterator iter;
screen_manager* screen;
void applySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination);
};
#endif
It seems, this line
void applySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination){
wants to read
void scene_manager::applySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination){
You need the scope resolution operator when you define the applySurfacefunction outside the class.
void scene_manager::applySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination){
//^^^^^^^^^^^^^