I am trying to build a simple game engine with C++ and SDL. I am going through and trying to take the things that I know work in one big .cpp file, and organizing them into more logical patterns. For example, having a Game class, that contains a Screen or Engine class, a Logic class, an Entities class, etc. Obviously doesn't need to be super advanced as I'm just trying to get a handle for the first time on setting up things logically. Unfortunately I get the linker errors:
1>game.obj : error LNK2019: unresolved external symbol "public: __thiscall Screen::~Screen(void)" (??1Screen##QAE#XZ) referenced in function "public: __thiscall Game::Game(void)" (??0Game##QAE#XZ)
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall Game::~Game(void)" (??1Game##QAE#XZ) referenced in function _SDL_main
And the SDL is definitely set up properly, because the code executes just fine when everything is in one big file.
So far I have a Game class, and a Screen class.
game.h
#ifndef GAME_H
#define GAME_H
// Includes
#include "screen.h"
// SDL specific includes
#include "SDL.h"
class Game
{
private:
Screen screen;
public:
Game();
~Game();
};
#endif
game.cpp
#include "game.h"
Game::Game()
{
Screen screen;
}
screen.h
#ifndef SCREEN_H
#define SCREEN_H
#include "SDL.h"
class Screen
{
private:
// Screen dimension variables
int SCREEN_WIDTH, SCREEN_HEIGHT;
// --SDL object variables--
// The window we'll be rendering to
SDL_Window * window;
// The surface contained by the window
SDL_Surface * screenSurface;
public:
Screen();
~Screen();
// Functions for calling SDL objects
SDL_Window *getSDLWindow( void );
SDL_Surface *getSDLSurface( void );
};
#endif
screen.cpp
#include "screen.h"
#include <stdio.h>
Screen::Screen()
{
// Initialize window and SDL surface to null
window = NULL;
screenSurface = NULL;
// Initialize screen dimensions
SCREEN_WIDTH = 800;
SCREEN_HEIGHT = 600;
// Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
}
else
{
// Create a window
window = SDL_CreateWindow( "The First Mover", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if (window == NULL)
{
printf ("Window could not be created! SDL Error: %s\n", SDL_GetError() );
}
else
{
// Get window surface
screenSurface = SDL_GetWindowSurface( window );
// Fill the surface white
SDL_FillRect( screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0xFF, 0xFF, 0xFF) );
}
}
}
Any assistance appreciated! Also, if anyone has any ideas on how to better organize what I'm trying to do, feel free to comment!
Since you have declared the destructors for Screen and Game you need to provide definitions for them too. Add this in the Game.cpp and Screen.cpp files:
Game::~Game(){
// what ever you need in the destructor
}
Screen::~Screen(){
// what ever you need in the destructor
}
If you hadn't declared the destructors the compiler would have generated an implicitly for you.
Related
I'm trying to set up an SDL project with Visual Studio 2019 using this article:
https://www.wikihow.com/Set-Up-SDL-with-Visual-Studio
but the compiler is throwing me the errors 'one or more multiply defined symbols found' and
'_main already defined in main.obj'.
main.obj is a file in the debug folder of my project but when I try deleting it or the entire debug folder, VS recreates it when I run the project.
I've read that c++ can't have more than one main function but I can't open the main.obj file and I don't really want to delete the one in main.cpp
Here's the code I'm running and thanks for your help!
#include "SDL.h"
#include <stdio.h>
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow
("An SDL2 window", // window's title
10, 25, // coordinates on the screen, in pixels, of the window's upper left corner
640, 480, // window's length and height in pixels
SDL_WINDOW_OPENGL);
SDL_Delay(3000); // window lasts 3 seconds
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Glad to know it works now. Maybe you had a messy file structure with your previous SDL installation. Anyways, I think it might be interesting to show how the SDL dependency can be removed from your main.cpp file, to avoid such problems in the future.
First, let's consider the example in your question. The example is not very useful in practice, but I'll show a better version after.
The main idea is hiding everything that has to do with SDL from your main.cpp and headers.
1. Simple Example
// MySDL.h - NO SDL STUFF
class MySDL
{
public:
MySDL() = default; // or whatever you need
void runtest() const; // here we'll run the 3sec window
};
Now, we can put all our SDL stuff in the cpp file:
// MySDL.cpp
#include "MySDL.h"
#include "SDL.h" // HERE WE INCLUDE SDL
void MySDL::runtest()
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window* window = SDL_CreateWindow("yee haw", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Delay(3000);
}
No SDL included in main.cpp, we just include our SDL interface MySDL.h.
// Now you can use your SDL interface like this
int main(int, char* [])
{
MySDL sdl;
sdl.runtest();
return 0;
}
2. Better Version
However, you would typically want something more sofisticated than a window which disappears in 3 seconds. Therefore, you might want to store class members which depends on SDL. But then, you would have to #include "SDL.h" in your MySDL.h header file, which would give you the same problems as described in your question and comments. To remove this dependency, we can use the pimpl idiom.
The header file now includes a pointer to our SDL implementation. This SDL implementation will be defined in the cpp file in order to remove the SDL dependency.
// MySDL.h
class MySDL
{
public:
MySDL() = default; // or whatever you need
~MySDL();
void doSmthWithYourWindow(/*args*/);
private:
// pointer to our SDLImplementation (defined in cpp file)
class SDLImplementation;
std::unique_ptr<SDLImplementation> _sdl;
};
In our cpp file, we define the SDLImplementation, and MySDL has access to that implementation through the _sdl pointer.
// MySDL.cpp
#include "MySDL.h"
#include "SDL.h"
// here we can store class members which depend on SDL
struct MySDL::SDLImplementation
{
SDLImplementation()
{
SDL_Init(SDL_INIT_EVERYTHING);
_window = SDL_CreateWindow("yee haw", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_SHOWN);
_renderer = SDL_CreateRenderer(_window, -1, 0);
SDL_SetRenderDrawColor(_renderer, 0, 255, 0, 255);
SDL_RenderClear(_renderer);
SDL_RenderPresent(_renderer);
}
// functionality of your SDL implementation
void turnWindowUpsideDown() { /* _window->turnUpsideDown(); */ }
// members depending on SDL
SDL_Window* _window;
SDL_Renderer* _renderer;
};
MySDL::~MySDL() = default;
void MySDL::doSmthWithYourWindow(/*args*/)
{
// here we have access to our SDL implementation
_sdl->turnWindowUpsideDown();
}
Just like before, we only include our MySDL.h interface in the main.cpp file.
int main(int, char* [])
{
MySDL sdl;
sdl.doSmthWithYourWindow();
return 0;
}
So I ended up deleting SDL and completely restarting with a different tutorial linked here:
https://www.youtube.com/watch?v=QQzAHcojEKg
Not really sure what the difference was but it worked. Anyways, thanks for your help and I'll put the new code here.
#include "SDL.h"
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window* window = SDL_CreateWindow("yee haw", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Delay(3000);
return 0;
}
I can not for the life of me figure out why the implementation functions aren't being seen and the call to the constructor is unresolved. Any ideas would be appreciated.
Error:
1>Debug\MeGLWindow.obj : warning LNK4042: object specified more than once; extras ignored
1>MeApp.obj : error LNK2019: unresolved external symbol "public: __thiscall MeGLWindow::MeGLWindow(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0MeGLWindow##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z) referenced in function "public: __thiscall MeApp::MeApp(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0MeApp##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
1>C:\Users\FrizzleFry\documents\visual studio 2012\Projects\ConsoleApplication1\Debug\ConsoleApplication1.exe : fatal error LNK1120: 1 unresolved externals
App Header
#ifndef ME_APP
#define ME_APP
#include "MeGLWindow.h"
#include <string>
class MeApp {
private:
MeGLWindow* meWind;
std::string app;
public:
MeApp() {}
MeApp(std::string);
~MeApp();
void run();
};
#endif
The implementation
#include "MeApp.h"
#include <SDL.h>
#include <gl\glew.h>
#include <SDL_opengl.h>
#include <gl\glu.h>
#include <string>
MeApp::MeApp(std::string appName) {
app = appName;
meWind = new MeGLWindow(app);
}
MeApp::~MeApp() {
//delete[] meWind;
//meWind = NULL;
}
void MeApp::run() {
bool quit = false;
//Event handler
SDL_Event e;
//Enable text input
SDL_StartTextInput();
//While application is running
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
//Handle keypress with current mouse position
else if( e.type == SDL_TEXTINPUT )
{
int x = 0, y = 0;
SDL_GetMouseState( &x, &y );
//handleKeys( e.text.text[ 0 ], x, y );
}
//meWind->show();
}
//Disable text input
SDL_StopTextInput();
}
}
The window header and implementation:
#ifndef ME_GL_WINDOW
#define ME_GL_WINDOW
#include "SDL.h"
#include "GL\glew.h"
#include "SDL_opengl.h"
#include "GL\glu.h"
#include <string>
class MeGLWindow {
private:
std::string appName;
int SCREEN_WIDTH, SCREEN_HEIGHT;
SDL_Window* meWind;
SDL_GLContext meContext;
public:
MeGLWindow() {}
MeGLWindow(std::string);
~MeGLWindow();
void show();
};
#endif
cpp
#include <SDL.h>
#include <gl\glew.h>
#include <SDL_opengl.h>
#include <gl\glu.h>
#include <string>
#include "MeGLWindow.h"
#include <iostream>
#include <string>
MeGLWindow::MeGLWindow(std::string app) {
appName = app;
if(SDL_Init( SDL_INIT_VIDEO) < 0) {
std::cout << "Failed to initilialize SDL!" << std::endl;
exit(1);
}
SCREEN_HEIGHT = 640;
SCREEN_WIDTH = 480;
//Use OpenGL 3.1 core
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
//Create window
meWind = SDL_CreateWindow( appName.c_str() , SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN );
if( meWind == NULL )
{
std::cout << "Failed to create window!" << std::endl;
exit(2);
}
meContext = SDL_GL_CreateContext( meWind );
if( meContext = NULL ) {
std::cout << "Failed to create GL Context!" << std::endl;
exit(3);
}
glewExperimental = GL_TRUE;
GLenum glewerror = glewInit();
if( glewerror != GLEW_OK )
{
std::cout << "Error initializing GLEW!" << std::endl;
exit(4);
}
//use vsync
if( SDL_GL_SetSwapInterval( 1 ) < 0 )
{
std::cout << "Unable to set vsync!" << std::endl;
//printf( "warning: unable to set vsync! sdl error: %s\n", sdl_geterror() );
}
//initialize opengl
//( !initgl() )
}
MeGLWindow::~MeGLWindow() {
//glDeleteProgram( gProgramID );
//Destroy window
SDL_DestroyWindow( meWind );
meWind = NULL;
//Quit SDL subsystems
SDL_Quit();
}
void MeGLWindow::show() {
glClear( GL_COLOR_BUFFER_BIT );
SDL_GL_SwapWindow( meWind );
}
call file
#include <SDL.h>
#include <gl\glew.h>
#include <SDL_opengl.h>
#include <gl\glu.h>
#include <stdio.h>
#include <string>
#include "MeApp.h"
int main( int argc, char* args[] )
{
MeApp app("My Application");
app.run();
return 0;
}
EDIT
Well, I thought that maybe the .obj file was corrupted and had tried deleting it and rebuilding. They were rebuilt but still gave me this error.
If I introduce non-sensical code (I added the line a in the MeGLWindow.h as a class member) and the build gloriously failed due to:
1>c:\users\frizzlefry\documents\visual studio 2012\projects\consoleapplication1\consoleapplication1\meglwindow.h(22): error C2146: syntax error : missing ';' before identifier 'MeGLWindow'
1>c:\users\frizzlefry\documents\visual studio 2012\projects\consoleapplication1\consoleapplication1\meglwindow.h(22): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>
1>Build FAILED.
I then went to the project directory and deleted the entire debug folder save the two .dll files.
I then deleted the nonsensical code and rebuilt the solution to no avail. I received the same unresolved external symbol error.
When I originally created the files, I accidently named the file meGLWindow.h and I started getting this error after renaming the file. It wouldn't let me just rename the file with a capital, it would say that the file already existed. So I renamed it to something different, (2MeGLWindow.h) and then deleted the original file in the project folder and renamed it back to MeGLWindow.h
Then this error occured (but I had added code and didn't think this was the cause) especially since if I remove the MeGLWindow function calls (like new MeGLWindow(app);) then no build error occurs. It's only if I try to have either the main function or the app class create an instance of MeGLWindow.
I'm considering just copy pasta into a new solution. But maybe there are some sort of list of source files in the solution that are pointing to the wrong meGLWindow.h file that I originally created?
EDIT2
Just got fed up, it was 5 files. I made a new project, copy pasted the header and cpp files and it works like a charm. I will never simply rename a header file ever again.
Warning LNK4042 is a bit deceptive, actually it means that object FILE was specified more that once, so for some reason you already have MeGLWindow.obj, and it does not contain a symbol for the MeGLWindow(std::string), hence the error. Possible reasons are:
Build can't delete old MeGLWindow.obj from the times when that constructor was not implemented yet.
Build doesn't even try to delete old MeGLWindow.obj.
Some other MeGLWindow.obj pops up in the build before the proper one.
Solution: try clean build/rebuild/manually deleting Debug/MeGLWindow.obj; Carefully check build options, output file names. Check security/UAC/access rights. Hopefully that helps.
I am currently attempting to write a very simple 2d game engine using SDL in order to help myself get more comfortable with coding. Unfortunately, I made the mistake of starting with a single source file, and now that my code is getting bigger, I am trying to split the existing code (which works fine before the split) into multiple header and source files. The first major issue I've encountered is that when I try to define SCREEN_HEIGHT, SCREEN_WIDTH, Window, and Renderer in init.cpp after declaring them in init.h, I get error: 'blank' does not name a type (blank being Window, Renderer, etc.). I am also trying to make them global, which may be part of the issue. Included below is the relevant code (I took out all the stuff I think is irrelevant in this case). I suspect I'm just missing something really simple here, but I've been unable to find an existing answer online like I have with my previous problems.
main.cpp
#include "globals.h"
#include "texture.h"
....
globals.h
#ifndef GLOBALS
#define GLOBALS
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <stdio.h>
#include <string>
#endif //GLOBALS
texture.h
#ifndef TEXTURE
#define TEXTURE
#include "globals.h"
#include "init.h"
....
#endif // TEXTURE
texture.cpp
#include "texture.h"
....
init.h
#ifndef INIT
#define INIT
#include "globals.h"
//screen dimensions
int SCREEN_WIDTH;
int SCREEN_HEIGHT;
//initiates SDL and creates a window and renderer
bool init();
//the created window
SDL_Window* Window;
//the renderer that will be used
SDL_Renderer* Renderer;
#endif // INIT
init.cpp
#include "init.h"
SCREEN_WIDTH = 640;
SCREEN_HEIGHT = 480;
Window = NULL;
Renderer = NULL;
bool init()
{
bool success = true;
if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
printf( "SDL was unable to initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1"))
{
printf( "Linear texture filtering not enabled!");
}
else
{
Window = SDL_CreateWindow( "Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if( Window == NULL)
{
printf( "Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
Renderer = SDL_CreateRenderer( Window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if( Renderer == NULL)
{
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
SDL_SetRenderDrawColor( Renderer, 0xFF, 0xFF, 0xFF, 0xFF);
int PNGImage = IMG_INIT_PNG;
if( !(IMG_Init( PNGImage) & PNGImage))
{
printf( "Image loading not enabled! SDL_Image Error: %s\n", IMG_GetError());
success = false;
}
if( TTF_Init() == -1)
{
printf( "True type fonts not enabled! SDL_TTF Error: %s\n", TTF_GetError());
success = false;
}
}
}
}
}
return success;
}
I get the error in init.cpp at the top of the code before bool init()
Renderer = NULL; is an assignment statement, which you cannot have in global scope. You can only have declarations in global scope. Since you have already declared Renderer in your header file, you don't need to redeclare it either. Just set it to null within one of your initialization functions (e.g. your current init() function).
I have recently purchased a new laptop and got a new version of VS from my school. And I'm having a little trouble setting up my libraries.
I created a basic SDL_Window, as well as a SDL_GLContext.
I'm able to include my libraries and run the program, but I can't call functions like glClearColor, or glGetString(GL_VERSION). I get a rather strage warning and an error that I have never seen before, I'm guessing it's related to the 2013 version?
I have tried ignoring all specific default libraries, as well as trying to change the programtype (Multithreaded DLL, those 4).
And I have made sure all the dll-files are in place in my system folder.
What makes me wonder is the fact that glewInit() works, but not glClearColor() etc...
Output:
1>MSVCRTD.lib(cinitexe.obj) : warning LNK4098: defaultlib 'msvcrt.lib'
conflicts with use of other libs; use /NODEFAULTLIB:library
1>Window.obj : error LNK2019: unresolved external symbol
__imp__glClearColor#16 referenced in function "public: void __thiscall Window::initOpenGL(void)" (?initOpenGL#Window##QAEXXZ)
1>C:\Users\Aleksander\documents\visual studio 2013\Projects\OpenGL
Test\Debug\OpenGL Test.exe : fatal error LNK1120: 1 unresolved
externals
Header:
#pragma once
#include <SDL.h> //Tested OK
#include <SDL_image.h> //Tested OK
#include <SDL_mixer.h> //Tested OK
#include <SDL_net.h> //Tested OK
#include <OpenGL\glew.h> //?
#include <freeglut\freeglut.h> //?
#include <gl\GL.h> //?
#include <glm\glm.hpp> //Tested OK
#include <iostream> //Standard OK
#include <Box2D\Box2D.h> //Tested OK
using namespace std;
class Window {
SDL_Window *window;
SDL_GLContext context;
bool quit;
public:
Window();
~Window();
void initSDL();
void initOpenGL();
void run();
};
Source:
#include "Window.h"
Window::Window() {
printf("Starting window...\n");
//Initialize window
quit = false;
initSDL();
initOpenGL();
//Run window
run();
}
Window::~Window() {
printf("Closing window...\n");
//Clear window memory
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
//Close window library
SDL_Quit();
}
void Window::initSDL() {
if (SDL_Init(SDL_INIT_EVERYTHING) == -1) {
quit = true;
printf("Unable to initialize SDL!\n");
}
else {
//Create window
const char *title = "OpenGL Test";
int pos = SDL_WINDOWPOS_CENTERED;
int w = 800;
int h = 600;
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
window = SDL_CreateWindow(title, pos, pos, w, h, flags);
//Create OpenGL context
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
context = SDL_GL_CreateContext(window);
}
}
void Window::initOpenGL() {
GLenum init = glewInit();
if (init != GLEW_OK) {
quit = true;
printf("Unable to initialize OpenGL!\n");
printf("Error: %s!\n", glewGetErrorString(init));
}
else {
//printf("Vendor: %s\n", glGetString(GL_VENDOR));
//printf("Version: %s\n", glGetString(GL_VERSION));
//printf("Renderer: %s\n", glGetString(GL_RENDERER));
}
}
void Window::run() {
printf("Window started running!\n");
SDL_Event event;
while (!quit) {
SDL_GL_SwapWindow(window);
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
}
}
I'm a beginner at C++ programming (worked with PHP for years) and am having some trouble with getting Visual Studio Express 2013 to compile some code that works fine in both Xcode and Eclipse.
So the setup is this. I'm aiming to create a game for phones and tablets using SDL 2.0. I'm working a Mac (using a VM for Windows) and have so far successfully got initial test projects working in both Xcode and Eclipse. Both projects link to a common library created using Xcode (for cross-platform development, so I code once for all platforms). I am now trying to add the appropriate Visual Studio project so that I can also compile it for Windows 8/WP8.
Following the instructions here I have successfully managed to get the basic test on that page working, proving that SDL is functioning in Windows 8. However, I am now struggling to link my common library to the project in Visual Studio, which keeps giving me errors. First the code.
main.cpp
#include "SDL.h"
#include "rectangles.h"
#include <time.h>
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 480
int main(int argc, char *argv[])
{
SDL_Window *window;
SDL_Renderer *renderer;
int done;
SDL_Event event;
/* initialize SDL */
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("Could not initialize SDL\n");
return 1;
}
/* seed random number generator */
srand(time(NULL));
/* create window and renderer */
window =
SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_OPENGL);
if (!window) {
printf("Could not initialize Window\n");
return 1;
}
renderer = SDL_CreateRenderer(window, -1, 0);
if (!renderer) {
printf("Could not create renderer\n");
return 1;
}
Rectangles rectangles(SCREEN_WIDTH, SCREEN_HEIGHT);
/* Enter render loop, waiting for user to quit */
done = 0;
while (!done) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
done = 1;
}
}
rectangles.render(renderer);
SDL_Delay(1);
}
/* shutdown SDL */
SDL_Quit();
return 0;
}
rectangles.h
#ifndef RECTANGLES_H
#define RECTANGLES_H
class Rectangles {
public:
int screenWidth;
int screenHeight;
Rectangles(int width, int height);
void render(SDL_Renderer *renderer);
int randomInt(int min, int max);
};
#endif
rectangles.cpp
#include "SDL.h"
#include "Rectangles.h"
Rectangles::Rectangles(int width, int height)
{
screenWidth = width;
screenHeight = height;
SDL_Log("Initializing rectangles!");
}
int Rectangles::randomInt(int min, int max)
{
return min + rand() % (max - min + 1);
}
void Rectangles::render(SDL_Renderer *renderer)
{
Uint8 r, g, b;
/* Clear the screen */
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
/* Come up with a random rectangle */
SDL_Rect rect;
rect.w = randomInt(64, 128);
rect.h = randomInt(64, 128);
rect.x = randomInt(0, screenWidth);
rect.y = randomInt(0, screenHeight);
/* Come up with a random color */
r = randomInt(50, 255);
g = randomInt(50, 255);
b = randomInt(50, 255);
SDL_SetRenderDrawColor(renderer, r, g, b, 255);
/* Fill the rectangle in the color */
SDL_RenderFillRect(renderer, &rect);
/* update screen */
SDL_RenderPresent(renderer);
}
The code I'm using is slightly modified from a tutorial on using the SDL. I moved the sections for drawing the rectangles from a function in main.cpp to their own class. This compiles and runs fine in both Xcode (iOS) and Eclipse (Android). I added the location of the rectangles.h file to the "Additional Include Directories" option in Visual Studio, but it gives the following errors:
Error 2 error LNK2019: unresolved external symbol "public: __thiscall Rectangles::Rectangles(int,int)" (??0Rectangles##QAE#HH#Z) referenced in function _SDL_main Z:\Desktop\SDLWinRTApplication\SDLWinRTApplication\main.obj SDLWinRTApplication
Error 3 error LNK2019: unresolved external symbol "public: void __thiscall Rectangles::render(struct SDL_Renderer *)" (?render#Rectangles##QAEXPAUSDL_Renderer###Z) referenced in function _SDL_main Z:\Desktop\SDLWinRTApplication\SDLWinRTApplication\main.obj SDLWinRTApplication
Error 4 error LNK1120: 2 unresolved externals Z:\Desktop\SDLWinRTApplication\Debug\SDLWinRTApplication\SDLWinRTApplication.exe SDLWinRTApplication
I've looked at several answers that indicate it is something wrong with my code, but I can't see what I've done wrong? Or is there an additional step I need to make in Visual Studio to get this working?
The end goal is to have individual projects for each platform, that call on a common library where the actual "game" exists so I'm not copying files back and forth for each platform (asked about it previously here).
Many thanks.
EDIT:
As per advice, I have tried adding the rectangles.cpp file to the project solution in Visual Studio again. However, I then get the following errors that I can't make head nor tail of.
Error 2 error LNK2038: mismatch detected for 'vccorlib_lib_should_be_specified_before_msvcrt_lib_to_linker': value '1' doesn't match value '0' in MSVCRTD.lib(appinit.obj) Z:\Desktop\SDLWinRTApplication\SDLWinRTApplication\vccorlibd.lib(compiler.obj) SDLWinRTApplication
Error 3 error LNK2005: ___crtWinrtInitType already defined in MSVCRTD.lib(appinit.obj) Z:\Desktop\SDLWinRTApplication\SDLWinRTApplication\vccorlibd.lib(compiler.obj) SDLWinRTApplication
Error 4 error LNK1169: one or more multiply defined symbols found Z:\Desktop\SDLWinRTApplication\Debug\SDLWinRTApplication\SDLWinRTApplication.exe SDLWinRTApplication
EDIT2:
If I remove the reference to the location of rectangles.h from the "Additional Include Directories", and add the rectangles.h to the project solution alongside the rectangles.cpp file, I then get:
Error 1 error C1083: Cannot open include file: 'Rectangles.h': No such file or directory z:\desktop\sdlwinrtapplication\sdlwinrtapplication\main.cpp 8 1 SDLWinRTApplication
According to the question here, Visual Studio should be able to find the header file when it is added to the project root?
You have to "export" the public interface of your Rectangle class by adding something to rectangles.h. Instructions are at "add a class to the dynamic link library" on this page:
https://msdn.microsoft.com/en-us/library/ms235636.aspx
Also make sure that everything is for the same platform; all x64 or all Win32 for example. To see the platform of each project in the solution, right click the solution and the click on "Configuration Properties".