I'm trying to use the SFML library to create a sort of text interface in c++, but i ran into an error trying to load a font.
My code looks like this
sf::Font font;
if (!font.loadFromFile("courbd.ttf"))
{
std::cout << "Can't load the font file" << std::endl;
}
and both the code I'm trying to load the font from and the font are in this path:
C:\Users\Computer\Desktop\PruebaSFML\PruebaSFML
I tried using the whole path to load the font but that didn't work either.
Normally, loadFromFile is going to take a path starting from the file the code is in. Here is an example from when I worked with SFML:
if (!font.loadFromFile("Ressources\\Fonts\\CrimsonText.ttf"))
return false;
The cpp file is at the same level of the Ressources folder. Also, dont forget to use 2x \ to escape the character, because it's used to make instruction in the string like \n for a new line. So make sure of the location of the font file from the cpp file and if you need to use a path, use \ to separate folders.
Related
Alright so I'm trying to make a game engine for myself, and I've decided that it would be best to start loading images as files other than bitmaps using the SDL Image library. I've set up the library correctly according to conversations online, include set up and linker set up, and yet when I try to load a file that does indeed exist it just returns an empty surface.
Heres the code loading the file...
SDL_Surface* background = IMG_Load("Assets/bg.png");
background = SDL_ConvertSurface(background, mtrx->format, 0);
if (!background) {
ofstream file("text.txt");
file << IMG_GetError() << endl;
file.close();
}
...And the error I get in "text.txt"...
Parameter 'surface' is invalid
At the beginning of the script I have included SDL.h, then SDL_image.h, and the window initiation has IMG_Init(IMG_INIT_PNG) after SDL_Init. Visual studio shows no errors whatsoever, and everything BUT IMG_Load works fine.
All help would be appreciated, and I can provide any other code that might be helpful!
Many of you have probably wondered- how can I get rid of a font or any other single file from the drive when using a library like SFML, which needs to load a font from a file path.
So, how do I embed that data into the executable, so the resulting executable does not depend on those resource files anymore?
First of all, we have to get our resource. I have downloaded "BalooBhaijaan-Regular.ttf" font from google fonts.
Then, one should get the binary data of the given font. The easiest way to achieve this in my opinion is to use the linux "xxd" command with -i parameter which outputs in a C-style array.
Let's redirect the output to a file because It is usually going to be long if we are talking about true type fonts or larger images:
xxd -i BalooBhaijaan-Regular.ttf > font_data.txt
Create an empty C/C++ header or put the font data into an already existing file. I prefer using new header files as the output is going to be really long.
Of course, after pasting into your IDE you can change the array type to const as the content of a font usually doesn't change.
This is how it looks in my IDE:
You might of course wonder why is this a char array - simply because in a char array each "field" represents one byte.
As you might have noticed, xxd also creates another variable for us - the last variable in the font_data.txt is an unsigned int which informs us about the length of the array. We will need this later. Name of the "length-informing" integer is same as name of the array with "_len" suffix
Now, there are two ways to proceed:
1. load font from the memory using a builtin method (some libraries support it, SFML does)
2. create a "fake" file and load it
Lets talk about both cases
1.
This one is fairly simple, sfml supports loading file from memory given it's address and size, so we can just do this:
#include "BalooBhaijaanFont.hpp"
#include <SFML/Graphics.hpp>
int main(int argc, char** argv) {
sf::RenderWindow mainWindow(sf::VideoMode(200,100), L"TEST");
sf::Font fromMem;
fromMem.loadFromMemory(&BalooBhaijaan_Regular_ttf, BalooBhaijaan_Regular_ttf_len);
sf::Text text("WORKS!", fromMem);
while(mainWindow.isOpen()){
mainWindow.draw(text);
mainWindow.display();
}
return 0;
}
As you can see, loading it with a builtin function is really easy.
2.
Now it's time for a temporary file approach which i really do NOT recommend - most libraries support loading from memory and if you are making your own library you are going to end with having a memory load function anyway.
Whilst it is still possible to create a file just to read it to a font class and then remove it, I do not see any sense of using this method unless you are extremely annoyed by additional files in your folders.
Just for reference:
#include "BalooBhaijaanFont.hpp"
#include <SFML/Graphics.hpp>
int main(int argc, char** argv) {
sf::RenderWindow mainWindow(sf::VideoMode(200,100), L"TEST");
sf::Font fromFile;
{
FILE * tempFile = fopen("tmpfont.ttf", "wb");
fwrite( BalooBhaijaan_Regular_ttf, sizeof(char), BalooBhaijaan_Regular_ttf_len, tempFile );
fclose(tempFile);
fromFile.loadFromFile("tmpfont.ttf");
std::remove("tmpfont.ttf");
}
sf::Text text("WORKS!", fromFile);
while(mainWindow.isOpen()){
mainWindow.draw(text);
mainWindow.display();
}
return 0;
}
For Windows you can do xxd -i Roboto-Bold.ttf > font_data.txt in git bash. This gives you a file with data that can be imported straight into your project.
I am trying to play a .mod audio file in an executable. I am using the 3rd party BASSMOD .dll. I can get the audio file to play when I provide the full path to the file, but I cannot get it to play when providing a relative path. Here are some snippets.
main.cpp
#include <QCoreApplication>
#include "bassmod.h"
// define file location
const char* file = "C:/Users/Downloads/test4/console/music.mod";
void startMusic() {
BASSMOD_Init(-1, 44100, 0);
BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);
BASSMOD_MusicPlayEx(0,-1,TRUE);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
startMusic();
return a.exec();
}
bassmod.h (relevant snippet)
BOOL BASSDEF(BASSMOD_MusicLoad)(BOOL mem, void* file, DWORD offset, DWORD length, DWORD flags);
The function I'm concerned about is BASSMOD_MusicLoad. As this project stands, the .mod file will play no problem. However, when I try to change the absolute path of the .mod file to a relative path ("music.mod"), the file fails to play. Why is that? I have the .mod file in the same directory as the executable as well as in the directory containing the .pro file -- that didn't seem to be the issue.
Also, maybe I'm missing something related to how files are opened in C++. It looks like the MusicLoad function requires that the second parameter be of type void*. I'm sure there are many different things I could be doing better here. Ideally, I'd like to be able to have file store the relative path to the .mod file and have it play that way so I don't have to hard code an absolute path. In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc, but then I would have to use QFile, I believe, which won't work because I need the type to be void*.
Any help for a beginner would be much appreciated.
EDIT 01: Thank you all for your help! I got it to work (using relative file path, at least). There are two ways to do this. Here's what I did and how I tested it:
The first case makes the assumption that BASSMOD (or whatever external dll you're using) does not handle relative paths.
const char* file = "C:/debug/music.mod"; // same dir as .exe
QFileInfo info("music.mod");
QString path = info.absoluteFilePath();
const string& tmp = path.toStdString();
const char* raw = tmp.data();
Those are the test items I set up. When I run BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);, it works as expected. That's when I hard-code the full absolute path.
When I ran BASSMOD_MusicLoad(FALSE,(void*)raw,0,0,BASS_MUSIC_RAMPS);, it didn't work. So I decided to print out the values for everything to see where it's messing up:
cout << "Qstring path: ";
qDebug() << path;
cout << "string& tmp: ";
cout << tmp << endl;
cout << "raw: ";
cout << raw << endl;
cout << "full char* file: ";
cout << file;
startMusic();
...returns this:
Qstring path:
"C:/myApp/build-Debug/music.mod"
string& tmp:
C:/myApp/build-Debug/music.mod
raw:
C:/myApp/build-Debug/music.mod
full char* file:
C:/myApp/build-Debug/debug/music.mod
Note the difference? When I hard-code the full path to the file, I found that (thanks to #FrankOsterfeld and #JasonC) the current working directory was actually not where the .exe (/debug) or .pro files were located. It was actually in the same directory as the Makefile.
So I just changed it to this: QFileInfo info("./debug/x.m"); and it worked.
Even though the problem wound up being me not knowing where the current working directory was, the solutions by #Radek, #SaZ, and #JasonC helped to find another way to solve this (plus it showed me how to get the working dirs and convert between types). This is a good reference for people who would want to use QFileInfo to determine where you actually are in the filesystem. I would have used this solution if the dll I was using did not handle relative paths well. However...
I wondered if I could apply the same solution to my original code (without using QFileInfo and converting types, etc). I assumed that BASSMOD did not handle relative paths out of the box. I was wrong. I changed the file variable to const char* file = "./debug/x.m"; It worked!
Thanks for the help, everyone!
However, I would still like to get this to work using music.mod from a Qt resources file. Based on the replies, though, it doesn't look like that's possible unless the 3rd party library you're using supports the Qt resource system.
I have the .mod file in the same directory as the executable.
In Qt Creator the default initial working directory is the directory that the .pro file is in, not the directory that the .exe ends up in.
Either put your file in that directory (the one that probably has all the source files and such in it as well, if you used the typical setup), or change the startup directory to the directory the .exe file is in (in the Run Settings area).
Although, based on your new comment below, I guess the problem is deeper than that... I can't really tell you why BASS doesn't like relative filenames but you can convert a relative path to an absolute one before passing it to BASS. There's a lot of ways to do that; using Qt's API you could:
#include <QFileInfo>
...
const char* file = "music.mod"; // Your relative path.
...
BASSMOD_MusicLoad(...,
(void*)QFileInfo(file).absoluteFilePath().toAscii().data(),
...);
In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc
You won't be able to do that because loading resources from .qrc files is a Qt thing and BASS presumably does not use Qt internally (just like e.g. you could not open a resource with fopen), and doesn't understand how to load resources embedded by Qt. I am not familiar with BASS but a cursory glance at this documentation shows that it also has the ability to play data from an in-memory buffer. So one approach would be to use Qt to load the resource into accessible memory and pass that buffer instead.
In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc, but then I would have to use QFile, I believe, which won't work because I need the type to be void*.
Why do you only belive? Read Qt Doc. It will work. Don't use class QFile but QFileInfo.
QFileInfo info(:/resourcePrefix/name);
QString path = info.absoluteFilePath();
void* rawPtr = (void*)path.toStdString().c_str();
I added this font to resource: BYekan.ttf
I want to use this font in my application. I've tried this :
QFont font(":/images/font/BYekan.ttf");
nLabel->setFont(font);
nLabel->setText(tr("This is for test"));
layout->addWidget(nLabel);
But, I guess it's not working. How to use it?
Edit:
After reading this question , I've tried again :
int fontID(-1);
bool fontWarningShown(false);
QFile res(":/images/font/Yekan.ttf");
if (res.open(QIODevice::ReadOnly) == false) {
if (fontWarningShown == false) {
QMessageBox::warning(0, "Application", (QString)"Impossible d'ouvrir la police " + QChar(0x00AB) + " DejaVu Serif " + QChar(0x00BB) + ".");
fontWarningShown = true;
}
}else {
fontID = QFontDatabase::addApplicationFontFromData(res.readAll());
if (fontID == -1 && fontWarningShown == false) {
QMessageBox::warning(0, "Application", (QString)"Impossible d'ouvrir la police " + QChar(0x00AB) + " DejaVu Serif " + QChar(0x00BB) + ".");
fontWarningShown = true;
}
else
nLabel->setFont(QFont(":/images/font/Yekan.ttf", 10));
}
I compare this font and other font, but there isn't any different on Qt. why?
int id = QFontDatabase::addApplicationFont(":/fonts/monospace.ttf");
QString family = QFontDatabase::applicationFontFamilies(id).at(0);
QFont monospace(family);
In QML you can
FontLoader { id: font; source: "/fonts/font.otf" }
I had the same problem as reported in the original question. The above presented solution (answer beginning with the line "int id = QFontDatabase::addApplicationFont....) however did not work, as can be also seen in the comments above. addApplicationFont returned -1.
The reason is, that there is a leading ':' in the string for the call of the function addApplicationFont. I removed this. Now it works for me (testet with Qt 5.5.1 and Qt 4.8.6 on Linux) and returns 0. On Windows it might be necessary to add a drive letter in front.
Note: I had to provide the full path to the font file (e.g. /usr/share/fonts/ttf/droid/DroidSansFallbackFull.ttf)
No, see, I didn't do any of this. So for me, what I did was there's a ~/.font/ directory, if it doesn't exist you can create it.
Now you copy the ttf into this directory, and Linux will see it. However, in my case, I'm writing a QT application, so these fonts have names, so how does Linux know the name?
If you run the command:
fc-list
It dumps out all the font information systemwide and you can search for the font that you've added.
The output looks something like this:
...
/usr/share/texmf/fonts/opentype/public/lm/lmsans17-oblique.otf: Latin Modern Sans,LM Sans 17:style=17 Oblique,Italic
/home/XXX/.fonts/PAPYRUS.TTF: Papyrus:style=Regular,Normal,obyčejné,Standard,Κανονικά,Normaali,Normál,Normale,Standaard,Normalny,Обычный,Normálne,Navadno,Arrunta
/usr/share/fonts/X11/Type1/n019064l.pfb: Nimbus Sans L:style=Bold Condensed Italic
...
The parts of the output after the first colon on each line is the name of the font as it's seen from inside of Linux for that user. So these are "Latin Modern Sans,LM Sans 17" / "Papyrus" / "Nimbus Sans L". So Linux sees it, and all your applications running as your user will see them also, (Gimp, your Window Manager, QT applications etc etc etc)
Inside your QT application you call the one you are interested in, in my case i'm interested in Papyrus font:
tabWidget->setFont( QFont( "Papyrus",10 ) );
And then, sure enough the QT application just picks up the font...
If you wanted to make the font systemwide, then you'd have to locate the position of the font directories, from what i can see it's /usr/share/fonts/truetype/ you will need to create a subdirectory in there for your fonts but perhaps some other distros may be in a different location, you might want to double check that. Anyhow you can dump the ttf files in there. If you do that, you might want to consider running fc-cache -fv as this will treewalk through the truetype subdirectories seeking out newly added fonts.
With anything font related under Linux, run fc-list. It clears up all sorts of confusions and missunderstandings and sheds light on the otherwise dark and mysterious world of Linux fonts.
I have added an image "padimage.png" to my resources folder and set add to target and make copy if needed checked. Then in my c++ code I have the following code to check if it can reach the file
std::ifstream my_file("padimage.png");
if (my_file.good())
{
std::cout << "could read file \n";
} else {
std::cout << "could not read file \n";
}
This fails meaning I can't reach the file. I have checked in the debug build folder and the image is there under the resources folder, I have also tried alternative paths to the file like "resources/padimage.png" || Resources/padimage.png || ../Resources/padimage.png etc. etc.
I am fairly new to c++ still so I don't quite understand how it is suppose to find files or what path it searches relative to. Also I am sure this is quite an easy problem but I somehow can't solve it.
All help is much appreciated.
Just for your own sanity, do the following before anything else.
char wd[1024];
std::cout << getcwd(wd, sizeof(wd)) << std::endl;
You may be surprised at where you are, and thus why you can't open your file. When running from the IDE you can specify the location of your working directory under the Product/Edit Schemes... area of Xcode (among other places).
Thanks to a suggestion from WhozCraig I have managed to get it working by using the root of the project and then creating a standalone file next to the application like so:
./padimage.png
however this is not ideal. This means I would have resources outside of the project.
But after some trial and error I managed to navigate into the programs package contents by using .app to the package name;
./ProjectName.app/Contents/Resources/padimage.png