Original question:
I've been asked prior to a job interview to understand how an
anti-aliased line is drawn in a framebuffer, using C or C++. I haven't
used C, and it's been a few years for me since last using C++. I am a
complete beginner when it comes to graphics. My C++ experience has
mostly been in simple command-line programs and sorting methods. The
company does not care if I grab the code online, they want me to
understand it but still have a working executable.
I've used this tutorial to set up SDL libraries in MS VC++ 2012
Express, and this algorithm for the actual anti-aliasing. I have
a good understanding of the algorithm, though I'm currently having
trouble getting it to compile. I just want a line to be drawn, and
then I can go forward with setting the code up to the skeleton class
definitions I was given. This is what I have included aside from what
is on that page with the algorithm:
#include <cmath>
#include <math.h>
#include "conio.h"
#include "stdlib.h"
#include "stdio.h"
#include "SDL.h"
const double HEIGHT = 240;
const double WIDTH = 320;
const double X0 = 25.6;
const double X1 = 64.7;
const double Y0 = 30;
const double Y1 = 42;
int round(double number)
{
return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5);
}
void main()
{
Uint32 pixelColor = 00000000000000000000000000000000;
SDL_Surface* myScreen = SDL_CreateRGBSurface(SDL_ALPHA_OPAQUE,WIDTH,HEIGHT,32, 0x000000FF,
0x0000FF00, 0x00FF0000, 0xFF000000);
WULinesAlpha(X0, X1, Y0, Y1,pixelColor,myScreen);
return;
}
I'm getting the following errors:
Error 21 error LNK2019: unresolved external symbol _SDL_main
referenced in function _main Error 22 error LNK1120: 1 unresolved
externals
I've seen a few code examples saying the main function has to look
like this:
int main(int argc, char *argv[])
{
}
Again, graphics stuff is unfamiliar to me so I know my main function
is likely very wrong; I'm anticipating some shaking heads. Can someone
explain what is happening/what I need to do?
New:
I have now replaced my main function with the following code, based on NomNomNom069's YouTube video: "C++ SDL Tutorial 2 Creating a Screen and Handling Basic Input"
#include "SDL.h"
int main(int argc, char * args[])
{
bool running = true;
//initialize SDL
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
{
running = false;
}
//set up screen
SDL_Surface *screen;
screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_HWSURFACE);
if (screen == NULL)
{
running = false;
}
SDL_Event occur;
//main application loop
while (running)
{
SDL_PollEvent(&occur);
if (occur.type == SDL_QUIT)
{
running = false;
}
//drawing occurs here
SDL_FillRect(screen, NULL, 0);
SDL_Flip(screen);
}
//quit SDL
SDL_Quit();
return 0;
}
No errors, and I get a window to pop up. Awesome.
My question now is regarding how/where to call WuLinesAlpha. This function calls for 4 doubles, a Uint32 variable, and an SDL_Surface*. I have my doubles, I set the Uint32 to 0x000000FF, and I assume that the SDL_Surface I have set up as screen is the one passed in.
I've toyed around with where the WuLinesAlpha function call goes and I keep getting the black screen. I thought, as explained in the video, it would go in the loop but nothing has happened. Are there any more SDL commands I should be calling?
Fix your main declaration first. This does need to be int main(int argc, char *argv[]). Especially on Windows, since I believe SDL.h actually renames your main to some other name, and takes over main for the library itself.
Next, make sure you link against SDL properly. In my own SDL 1.2.x based project I have these lines in my Makefile:
SDL_CFLAGS := $(shell sdl-config --cflags)
SDL_LFLAGS := $(shell sdl-config --libs)
I then later append those flags to my actual CFLAGS and LFLAGS. Note that if you use make and Makefiles, you want to use := there, otherwise make will invoke the $(shell ...) command every time it expands $(CFLAGS).
I can't help you set up Microsoft's GUI products. This tutorial, for a slightly older MSVC product (2010), looks pretty good, and may put you on the right track: http://lazyfoo.net/SDL_tutorials/lesson01/windows/msvsnet2010e/index.php
And finally, don't forget to call SDL_Init() at some point, preferably before you start creating surfaces.
Good luck!
Related
I am trying to make a program that takes images and puts them on your wallpaper using a timer, but I kept getting the error "Timers can only be started with QThread", so I am trying to make this timer with more QThread elements (simpler designs like QThread::msleep haven't worked). Currently, my problem is that my calling slot for when the timer goes off is not working where it currently is, but if I put it in any other location, then the program spits out more errors as it is designed to go in that specific spot. The code itself is mainly a copy/paste of a bunch of other code, and I am new to QT, so I may be going about this completely wrong. If I am, I will gladly accept help so I can understand this better!
#include <mainwindow.h>
#include <mythread.h>
QMediaPlayer * BadAppleS = new QMediaPlayer();
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
int fileN = 0;
BadAppleS->setMedia(QUrl("qrc:/SongN/Bad Apple.mp3"));
BadAppleS->play();
mythread t;
t.start();
if (fileN <= 1625) {
void mythread::doIt(){ //Error here. No more errors elsewhere, though there may be in this function/signal.
QString fileNQ = QString::number(fileN);
QString filepath = (("qrc:/BAPics/scene (") + fileNQ + (")"));
char path[150];
wchar_t wtext[20];
strcpy_s(path, filepath.toStdString().c_str());
mbstowcs(wtext, path, strlen(path)+1);
LPWSTR pathp = wtext;
int result;
result = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pathp, SPIF_UPDATEINIFILE);
fileN++;
}
return app.exec();
}
}
Thank you for the help!
I've been having trouble with a game I've been working on, where once I added music it started segfaulting in my frequently-called texture-loading code, between 5-30 secs after it started playing. The best I could come up with was that it is some sort of memory corruption. After a good week of unsuccessfully trying to debug it (trying things like GFlags pageheap), I managed to cut it down to the following code, which still exhibits the problem.
Sometimes this segfaults with the callstack going through SDL2_mixer.dll, but mostly it occurs in the SDL_CreateTextureFromSurface call, due to the renderer being in a bad state. numTextures gets to between 15000-40000 on my machine (Windows 10 x64, with program compiled for x86).
My gut tells me that there's an issue in my environment or code, rather than an issue in SDL itself, but I'm at a loss. Any help or insights would be greatly appreciated.
#include <SDL_image.h>
#include <SDL_mixer.h>
#include <cassert>
int main(int argc, char* argv[])
{
assert(SDL_Init(SDL_INIT_EVERYTHING) == 0);
SDL_Window * pWindow_ = SDL_CreateWindow(
"", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0x0);
assert(pWindow_ != nullptr);
SDL_Renderer * pRenderer_ = SDL_CreateRenderer(pWindow_, -1, 0);
assert(pRenderer_ != nullptr);
assert(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 512) == 0);
Mix_Music * pMusic = Mix_LoadMUS("sounds/tranquility.wav");
assert(pMusic != nullptr);
assert(Mix_PlayMusic(pMusic, -1) == 0);
SDL_Surface * pSurface = IMG_Load("images/caution.png");
assert(pSurface != nullptr);
SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer_, pSurface);
assert(pTexture != nullptr);
int numTextures = 0;
while (true)
{
numTextures += 10;
assert(pTexture != nullptr);
SDL_DestroyTexture(pTexture);
pTexture = SDL_CreateTextureFromSurface(pRenderer_, pSurface);
assert(pTexture != nullptr);
}
}
The solution turned out to be to update to the latest version of SDL (2.0.3 -> 2.0.5).
I started developing the project in question with an engine code base which I upgraded from SDL 1.2 to 2.0 about 2 years ago, when the latest version was 2.0.3.
When I recently added sound and music, I took the latest SDL_mixer, and didn't think to update SDL to the latest 2.0.5.
After getting the latest development and runtime libraries for SDL (and SDL_image and SDL_mixer for good measure), the problem disappeared.
I'm not entirely satisfied with this. I'm quite surprised that the newer SDL_mixer linked successfully with an older SDL, if they were not compatible. In addition, I can't find any resources online that suggest any compatibility issues. Therefore, I have an uneasy feeling there may have been something else going on, which was resolved incidentally by the upgrade.
My goal is to build a Game Boy emulator. In order to do this, I would like to embed an SDL2 surface into a wxWidgets window.
I found this tutorial: http://code.technoplaza.net/wx-sdl/part1/, but my program crashes as soon as I run it. However I suspect this was intended for SDL1.2. Part of the program is shown below.
It seems that if I call SDL_Init() and also attempt to show a wxFrame (which, in this case, is MainWindow), it shows the window for a second and then the program crashes. I commented all other calls to SDL in my program so far, so it seems the problem lies with calling Show() on a wxFrame and initing SDL2 in the same program.
So the question is: can SDL2 and wxWidgets 3 work together? If not, could you guys suggest to me good alternatives a GUI of a Game Boy emulator? Does wxWidgets have its own graphics frame like Qt does (I'd rather avoid Qt)?
Thanks very much!
#include "MainApp.h"
#include "MainWindow.h"
#include <stdexcept>
namespace GBEmu {
static void initSDL() {
//This and SDL_Quit() are the only calls to the SDL library in my code
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
throw std::runtime_error("Fatal Error: Could not init SDL");
}
}
bool MainApp::OnInit()
{
try {
//If I comment out this line, the MainWindow wxFrame shows up fine.
//If I leave both uncommented, the window shows up quickly and then
//crashes.
initSDL();
//If I comment out this line and leave initSDL() uncommented,
//the program will not crash, but just run forever.
(new MainWindow("GBEmu", {50,50}, {640,480}))->Show();
} catch(std::exception &e) {
wxLogMessage(_("Fatal Error: " + std::string(e.what())));
}
return true;
}
int MainApp::OnExit() {
SDL_Quit();
return wxApp::OnExit();
}
}
wxIMPLEMENT_APP(GBEmu::MainApp);
EDIT: Here is more information on how it crashes: It crashes with a Segfault in what seems to be the pthread_mutex_lock disassembly file. This is the output in the console with stack trace:
Starting /home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx...
The program has unexpectedly finished.
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx crashed
Stack trace:
Error: signal 11:
/home/dan/Documents/devStuff/GBEmuWx-build/GBEmuWx(_ZN5GBEmu7handlerEi+0x1c)[0x414805]
/lib/x86_64-linux-gnu/libc.so.6(+0x36ff0)[0x7fb88e136ff0]
/lib/x86_64-linux-gnu/libpthread.so.0(pthread_mutex_lock+0x30)[0x7fb88c12ffa0]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XrmQGetResource+0x3c)[0x7fb88d1ca15c]
/usr/lib/x86_64-linux-gnu/libX11.so.6(XGetDefault+0xc2)[0x7fb88d1a7a92]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x94dcf)[0x7fb88af8edcf]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x97110)[0x7fb88af91110]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(cairo_surface_get_font_options+0x87)[0x7fb88af63e07]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2b61f)[0x7fb88af2561f]
/usr/lib/x86_64-linux-gnu/libcairo.so.2(+0x2ef95)[0x7fb88af28f95]
This is a screenshot of where it seems to fail (line 7):
Update: In my MainWindow class, I attach a menu bar to the window. However, it seems when I comment out the setting of the menu bar, the window will show up fine even with initing of SDL. The menu bar will show up fine if I have initSDL() commented out but not the setting of the menu bar. Here is where I set the menu bar:
MainWindow::MainWindow(const wxString &title, const wxPoint &pos, const wxSize &size)
:wxFrame(nullptr, wxIDs::MainWindow, title, pos, size){
wxMenu *fileMenu = new wxMenu;
fileMenu->Append(wxID_EXIT);
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append(fileMenu, "&File");
//commenting this line out will allow the window to showup
//and not crash the program
SetMenuBar(menuBar);
}
You are experiencing an old heisenbug.
The workaround is simple: you have to initialize SDL before wxWidgets (basically, before GTK). To achieve this, you have to change
wxIMPLEMENT_APP(GBEmu::MainApp);
to
wxIMPLEMENT_APP_NO_MAIN(GBEmu::MainApp);
so that wxWidgets doesn't hijack your main().
Then you have to create main() manually. In it, initialize SDL, then call wxEntry():
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cerr << "Could not initialize SDL.\n";
return 1;
}
return wxEntry(argc, argv);
}
More about the bug:
I have googled around a bit and found that this bug has come up in a few places over the years. There are open reports in many bug trackers that have stack traces very similar to the one you get here (with debug symbols).
The oldest report I could find is from 2005 (!!) from the cairo bug tracker (https://bugs.freedesktop.org/show_bug.cgi?id=4373).
My best guess is that the real hiding place of this bug in either in GTK, cairo, or X. Unfortunately I do not currently have the time to look into it more in depth.
I'm trying to learn OpenGL. I'm using the SFML window module for the context and gl3w as my loading library. I use SFML pretty often so it wasnt a problem to set it up for OpenGL following this tutorial:http://www.sfml-dev.org/tutorials/2.0/window-opengl.php
I could run the example code without any problems. I linked everything that I need for OpenGL (opengl32.lib and glu32.lib + sfml*.lib).
Then I followed this answer to get gl3w :How to set up gl3w on Windows?.
But now if I try to run this code which is mostly the example code from SFML
#include <SFML/gl3w.h>
#include <SFML/Window.hpp>
static const GLfloat red[] = { 1.0f, 0.f, 0.f, 1.f };
int main()
{
// create the window
sf::Window window(sf::VideoMode(800, 600), "OpenGL", sf::Style::Default, sf::ContextSettings(32));
window.setVerticalSyncEnabled(true);
gl3wInit(); //ignore return value for now
// load resources, initialize the OpenGL states, ...
// run the main loop
bool running = true;
while (running)
{
// handle events
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
// end the program
running = false;
}
else if (event.type == sf::Event::Resized)
{
//adjust the viewport when the window is resized
glViewport(0, 0, event.size.width, event.size.height);
}
}
glClearBufferfv(GL_COLOR, 0, red);
// end the current frame (internally swaps the front and back buffers)
window.display();
}
// release resources...
return 0;
}
I get following Linker errors.
1>OpenGL.obj : error LNK2019: unresolved external symbol _gl3wInit referenced in function _main
1>OpenGL.obj : error LNK2001: unresolved external symbol _gl3wViewport
1>OpenGL.obj : error LNK2001: unresolved external symbol _gl3wClearBufferfv
I double checked if I linked the libs correctly.
Im working on Windows 7 with Visual Studio 2013.
Anyone knows what I do wrong?
You forgot to compile gl3w.
Assuming that you already:
grabbed python script
ran it: python gl3w_gen.py
found gl3w.h glcorearb.h and gl3w.c files generated
There are two ways:
First way. Just include those files in your project, so it will be compiled along with your own sources. Note, that you need to preserve GL folder or manually fix includes in gl3w.c.
Second way. Create new project add all three files in it and compile as static library. Then link it to your application (or just compile it in command line or makefile, whatever).
Happy coding!
I'm using the following code (Allegro 4, C++), and getting the following error:
#include <allegro.h>
//defines
#define MODE GFX_SAFE
#define WIDTH 640
#define HEIGHT 480
int main (void)
{
int ret;
int counter;
//initialize allegro
allegro_init();
install_keyboard();
install_timer();
srand(time(NULL));
//set up screen
//set video mode
ret = set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0);
if (ret != 0)
allegro_message(allegro_error);
allegro_exit();
return 0;
}
Error:
1>MSVCRTD.lib(crtexe.obj) : error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup
All the previous answers regarding that error tell me to switch to "Console" from "Windows"; but I already have "Console" in Properties->Linker->System->Subsystem.
If you don't have an answer, I'd be happy with something I could do to help narrow down the problem: I've used Allegro with C, but I want to use C++ to take advantage of OOP, and so I still have a lot of work to do.
Update:
#include <iostream>
#include <allegro.h>
using namespace std;
int main ()
{
cout << "Hello World";
return 0;
}
doesn't work, but
#include <iostream>
using namespace std;
int main ()
{
cout << "Hello World";
return 0;
}
does.
Now what? Answer: Start with Empty project.
Update2: restarted with an empty project, same code. First block (alleg.lib in linker, but allegro.h not included) works, second code (allegro.h included) doesn't. However, the bug is different:
1>LINK : fatal error LNK1561: entry point must be defined
What now?
Edit^2:Ignore all the following: I forgot to go back to including Allegro. It works now. Thanks everyone for the answers.
Edit: Adding:
END_OF_MAIN()
or
int END_OF_MAIN()
give the error "fatal error C1004: unexpected end-of-file found"
You are getting the error because you are attempting to integrate allegro into a project that is non-empty.
You must create the project as an EMPTY PROJECT type:
New... > Project... > Visual C++ > Empty Project
--EDIT FOR SECOND ERROR--
You must append END_OF_MAIN() after the closing brace of int main():
int main() {
//...
}
END_OF_MAIN()