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".
Related
i have seen this error a lot in the setup of opengl, but now that it is working, there is this error now. all the rest is working just this and glClearColor isnt
i think that all the commands in gl.h and glew.h might not be working i havent tested yet, and yes they are added to the project as they should be, the libraries are loading well, but i just cant call functions from them. i was using glut and glew before with no problem, what might have happened in here?
#include<map>
#include<iostream>
#include<stdio.h>
#include<chrono>
#include<stdlib.h>
#define WIDTH 320
#define HEIGHT 200
struct key {
};
GLFWwindow* window;
GLFWmonitor* monitor;
bool running = 1, windowed;
std::map<int, key> keyMap;
void update(){}
void input(){}
void draw(){
glClear(GL_COLOR_BUFFER_BIT);
}
int main() {
glfwWindowHint(GLFW_SAMPLES, 1);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
if (!glfwInit()) fprintf(stderr, "opengl error\n");
window = glfwCreateWindow(WIDTH, HEIGHT, "end", NULL, NULL);
if (window == NULL) {std::cout << "window error\n" << std::endl; glfwTerminate();}
glfwMakeContextCurrent(window);
monitor = glfwGetPrimaryMonitor();
while (running)
{
update();
input();
draw();
}
glfwDestroyWindow(window);
glfwTerminate();
}
the errors are just these:
warning LNK4098: defaultlib 'MSVCRT' conflicts with use of other libs; use /NODEFAULTLIB:library
error LNK2019: unresolved external symbol __imp__wglGetProcAddress#4 referenced in function "void __cdecl draw(void)" (?draw##YAXXZ)
error LNK1120: 1 unresolved externals
So with created a window in C ++ using the GLFW library which also creates an OpenGL context. And after that I decided to add an icon to this window. There were 2 options, use either STB or SOIL to load the icon. I chose STB Image. I downloaded it and added it to my project. Everything works no errors, but for some reason my icon does not appear. It seems like the path I indicated is correct and included the path in the project in VS 2019.
Since I use premake5 to set the paths and to simplify the assembly, my path is specified how "%{prj.name}/libs/stb/include" and in VS 2019 there is just a path based on the name of the application libs/stb/include .
Here the image
And it's my code:
#define STB_IMAGE_IMPLEMENTATION
#include "CTXEngine/utils/stb_image.h"
void WinWindow::setIcon()
{
//stb load
GLFWimage images[2];
images[0].pixels = stbi_load("assets/textures/logo_16x16.png", &images[0].width, &images[0].height, 0, 4);
images[1].pixels = stbi_load("assets/textures/logo_32x32.png", &images[1].width, &images[1].height, 0, 4);
glfwSetWindowIcon(this->window, 1, images);
stbi_image_free(images[0].pixels);
stbi_image_free(images[1].pixels);
}
If you need see my window creating code, here it its:
#include "GLFW/glfw3.h"
/*
Intialize the WINDOWS GLFW library for window. If library is not
initialize, then application will be closed.
*/
void WinWindow::initLibrary()
{
if (!glfwInit())
{
this->glfwInitialized = false;
}
else
{
this->glfwInitialized = true;
}
if (!this->glfwInitialized)
{
CTX_ENGINE_ERROR("Glfw window is not initialized.")
CTX_ENGINE_INFO("Shuttdown internal servers...")
exit(-1);
}
}
/*
Create new WINDOWS GLFW window and create the context form graphical API
OpenGl.
*/
void WinWindow::createWindow()
{
CTX_ENGINE_INFO("Creating GLFW window...")
this->initLibrary();
/* Create a windowed mode window and its OpenGL context */
this->window = glfwCreateWindow(this->width, this->height, this->title, this->fullscreen ? glfwGetPrimaryMonitor() : NULL, NULL);
if (!window)
{
CTX_ENGINE_ERROR("Glfw window is not initialized.")
CTX_ENGINE_INFO("Shuttdown internal servers...")
this->terminateAPI();
exit(-1);
}
this->videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
/* Make the window's context current */
glfwMakeContextCurrent(this->window);
glfwSetWindowTitle(this->window, this->title);
glfwSetWindowSize(this->window, this->width, this->height);
glfwSetWindowAspectRatio(this->window, 16, 9);
glfwSetWindowSizeLimits(this->window, 854, 480, 1600, 900);
glfwSetWindowPos(this->window, ((this->videoMode->width - this->width) / 2),
((this->videoMode->height - this->height) / 2));
}
And finally code in the init function:
#include "CTXImportHeaders.h"
#include "CTXEngine/core/Core.h" //its just my class
#include "CTXEngine/core/CoreBehaviour.h" //its just my class
#include "CTXEngine/settings/GameSettings.h" //its just my class
using namespace std;
/*
This method be inititalize all core engine classes, structs, namespaces,
and other parameters, and configurations.
*/
void Core::init()
{
GameSettings settings;
this->window.setTitle(settings.gameTitle); // move params to game configuration
this->window.setWindowResolution(settings.gameWidth, settings.gameHeight); // move params to game configuration
this->window.setFullscreen(settings.gameFullscreen);
this->window.setIcon();
this->window.createWindow();
}
Its screenshot of my window without icon
I think you are confused in path. The path of the image should be relative to your .vcxproj files
├───assets
│ ├───Logos
| | |_ Icon.png
| |
│ ├───Shaders
│ └───textures
└───src
|
|___.vcxproj
I used this code:
int width, height, chennal;
stbi_uc* img = stbi_load("assets/Logos/Icon.png", &width, &height, &chennal, 0); //rgba channels
if (img == NULL) std::cout << "Icon Can Not Be Loaded\n";
m_Images->height = height;
m_Images->width = width;
m_Images[0].pixels = img;
glfwSetWindowIcon(m_Window, 1, m_Images);
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 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.
I'm new to C++ and i have been following a tutorial on how to make pong using C++ and SDL. I've been following the tutorial word by word but now I've hit a road block. When i try to run i get an error saying that my SDL functions are not being recognized.
The error i get is: fatal error C1083: Cannot open include file: 'SDLmain': No such file or directory
Here is my code:
#include "SDL.h"
#include"SDL_ttf.h"
SDL_Surface screen;
SDL_Event occur;
void loadGame()
{
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
SDL_Surface* hello = NULL;
SDL_Surface* screen = NULL;
screen = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
}
int main (int argc, char* args[])
{
loadGame();
bool running = true;
while(running == true)
{
}
return 0;
}
You should check your SDL lib and include paths. Make sure you've set the correct directories for your IDE to find the sdlmain files it needs.
Under VC++ Directories, Include directories, you should have C:\sdl2.0\include (or wherever you put SDL and its include subfolder), along with whatever else your projects need.
If this is already set... which version of SDL are you using (1.x or 2.x)? Is your version of SDL_TTF, and any other SDL add-ons, the same version?
Make sure that "SDL_main.h" is in the same folder as "SDL.h".
From "SDL.h":
//[...]
/**
* \file SDL.h
*
* Main include header for the SDL library
*/
#ifndef _SDL_H
#define _SDL_H
#include "SDL_main.h"
#include "SDL_stdinc.h"
#include "SDL_assert.h"
//[...]