c++ 包含SDL 2/SDL_Image时出现SDL包含错误

d7v8vwbk  于 2023-03-20  发布在  其他
关注(0)|答案(2)|浏览(285)

下面是一个简单的SDL2程序,它使用SDL_Image,运行良好:

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>

// Manage error messages
void check_error_sdl(bool check, const char* message);
void check_error_sdl_img(bool check, const char* message);

// Load an image from "fname" and return an SDL_Texture with the content of the image
SDL_Texture* load_texture(const char* fname, SDL_Renderer *renderer);

int main(int argc, char** argv) {
     // Initialize SDL
     check_error_sdl(SDL_Init(SDL_INIT_VIDEO) != 0, "Unable to initialize SDL");
 
     // Create and initialize a 800x600 window
     SDL_Window* window = SDL_CreateWindow("Test SDL 2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                                           800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
     check_error_sdl(window == nullptr, "Unable to create window");
 
     // Create and initialize a hardware accelerated renderer that will be refreshed in sync with your monitor (at approx. 60 Hz)
     SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
     check_error_sdl(renderer == nullptr, "Unable to create a renderer");
 
     // Set the default renderer color to corn blue
     SDL_SetRenderDrawColor(renderer, 100, 149, 237, 255);
 
     // Initialize SDL_img
     int flags=IMG_INIT_JPG | IMG_INIT_PNG;
     int initted = IMG_Init(flags);
     check_error_sdl_img((initted & flags) != flags, "Unable to initialize SDL_image");
 
     // Load the image in a texture
     SDL_Texture *texture = load_texture("img_test.png", renderer);
 
     // We need to create a destination rectangle for the image (where we want this to be show) on the renderer area
     SDL_Rect dest_rect;
     dest_rect.x = 50; dest_rect.y = 50;
     dest_rect.w = 337; dest_rect.h = 210;
 
     // Clear the window content (using the default renderer color)
     SDL_RenderClear(renderer);
 
     // Copy the texture on the renderer
     SDL_RenderCopy(renderer, texture, NULL, &dest_rect);
 
     // Update the window surface (show the renderer)
     SDL_RenderPresent(renderer);
 
     // Wait for 10 seconds
     SDL_Delay(5000);
 
     // Clear the allocated resources
     SDL_DestroyTexture(texture);
     IMG_Quit();
     SDL_DestroyRenderer(renderer);
     SDL_DestroyWindow(window);
     SDL_Quit();
 
     return 0;
}

// In case of error, print the error code and close the application
void check_error_sdl(bool check, const char* message) {
     if (check) {
         std::cout << message << " " << SDL_GetError() << std::endl;
         SDL_Quit();
         std::exit(-1);
     }
}

// In case of error, print the error code and close the application
void check_error_sdl_img(bool check, const char* message) {
     if (check) {
         std::cout << message << " " << IMG_GetError() << std::endl;
         IMG_Quit();
         SDL_Quit();
         std::exit(-1);
     }
}

// Load an image from "fname" and return an SDL_Texture with the content of the image
SDL_Texture* load_texture(const char* fname, SDL_Renderer *renderer) {
     SDL_Surface *image = IMG_Load(fname);
     check_error_sdl_img(image == nullptr, "Unable to load image");
 
     SDL_Texture *img_texture = SDL_CreateTextureFromSurface(renderer, image);
     check_error_sdl_img(img_texture == nullptr, "Unable to create a texture from the image");
     SDL_FreeSurface(image);
     return img_texture;
}

我编译它:

g++ -std=c++0x -Wall -pedantic sdl2_test.cpp -o sdl2_test `sdl2-config --cflags --libs` -lSDL2_image

它执行并正确显示图像。
然而,在我的游戏在同一个系统上,我得到这个错误时编译:

g++ -c frogmain.cc
In file included from level.hh:2,
                 from game.hh:1,
                 from frogmain.cc:2:
/usr/local/include/SDL2/SDL_image.h:27:10: fatal error: SDL.h: No such file or directory
 #include "SDL.h"
          ^~~~~~~
compilation terminated.
make: *** [makefile:5: frogmain.o] Error 1

下面是我的makefile:

FrogGame: frogmain.o game.o level.o sprite.o actor.o vector.o
    g++ -std=c++0x -Wall -pedantic -o FrogGame frogmain.o game.o level.o sprite.o actor.o vector.o `sdl2-config --cflags --libs` -lSDL2_image
    #g++ -o FrogGame frogmain.o game.o level.o sprite.o actor.o vector.o
    
frogmain.o: frogmain.cc game.hh level.hh sprite.hh vector.hh
    g++ -c frogmain.cc
    
game.o: game.cc level.hh sprite.hh actor.hh vector.hh
    g++ -c game.cc
    
level.o: level.cc sprite.hh actor.hh vector.hh
    g++ -c level.cc

actor.o: actor.cc vector.hh
    g++ -c actor.cc

sprite.o: sprite.cc vector.hh
    g++ -c sprite.cc

vector.o: vector.cc
    g++ -c vector.cc

唯一需要SDL的类是level类,下面是.cc文件:

#include <iostream>
#include <sys/time.h>
#include <chrono>
#include "level.hh"
#include "sprite.hh"
#include "actor.hh"
#include "vector.hh"
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

using namespace std;

level::level()
{
    this->levelPlaying = false;
    this->levelPaused = false;
    this->levelWon = false;
    this->curTime = 0;
    this->timeLimit = 0;
    this->screen = 0;
    this->renderer = 0;
    this->imageArray = 0;
    this->imLength = 0;
    
    this->createScreen();
}

void level::setLevelPlaying(bool p)
{
    this->levelPlaying = p;
}

bool level::getLevelPlaying()
{
    return this->levelPlaying;
}

void level::setLevelPaused(bool p)
{
    this->levelPlaying = p;
}

bool level::getLevelPaused()
{
    return this->levelPlaying;
}

void level::setLevelWon(bool p)
{
    this->levelWon = p;
}

bool level::getLevelWon()
{
    return this->levelWon;
}

void level::setCurTime(int t)
{
    this->curTime = t;
}

int level::getCurTime()
{
    return this->curTime;
}

void level::setTimeLimit(int t)
{
    this->timeLimit = t;
}

int level::getTimeLimit()
{
    return this->timeLimit;
}

bool level::createScreen()
{
    bool success = 0;
    //get size of screen
    SDL_DisplayMode dm;
    SDL_GetDesktopDisplayMode(0, &dm);
    if (dm.w < 1920 && dm.h < 1080)
    {
        screenW = dm.w;
        screenH = dm.h;
    }
    else
    {
        screenW = 1920;
        screenH = 1080;
    }

    success = this->checkSDLError(SDL_Init(SDL_INIT_EVERYTHING) == 0, "SDL Initialization failed");
    
    this->screen = SDL_CreateWindow("Test SDL 2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                                           screenW, screenH, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
    
    success = this->checkSDLError(this->screen, "Window Initialization failed");
    
    this->renderer = SDL_CreateRenderer(this->screen, -1, 0);
    success = this->checkSDLError(this->renderer, "Renderer Initialization failed");
    
    return success;
}

bool level::loadImageArrayToMemory(const char** imageNames, int length)
{
    IMG_Init(IMG_INIT_PNG);
    //allocate space for all textures
    this->imageArray = new SDL_Texture*[length];
    this->imLength = length;
    //run through entire list
    for (int i = 0; i < length; i++)
    {
        //load the image to a temp surface
        SDL_Surface* tmp = IMG_Load(imageNames[i]);
        this->checkSDLError(tmp, "Unable to load image");
        //create a texture from the surface, for hardware rendering
        this->imageArray[i] = SDL_CreateTextureFromSurface(this->renderer, tmp);
        this->checkSDLError(imageArray[i], "Unable to create texture");
        //destroy the surface
        SDL_FreeSurface(tmp);
    }
    return 1;
}

bool level::destroyImageArrayFromMemory()
{
    //loop through image array
    for (int i = 0; i < this->imLength; i++)
    {
        //destroy the texture in each index of the array
        SDL_DestroyTexture(imageArray[i]);
    }
    //delete the array
    delete[] imageArray;
    
    return 1;
}

bool level::loadSoundArrayToMemory()
{
    //TODO
    return 0;
}

bool level::destroySoundArrayFromMemory()
{
    //TODO
    return 0;
}

bool level::levelLoop()
{
    const int TPF = 33;
    auto curT = chrono::high_resolution_clock::now();
    auto prevT = curT;
    auto diff = 0;
    
    vector p(4,5);
    vector d(78,90);
    
    actor a(p, d, 1, 100);
    
    while (this->getLevelPlaying())
    {
        //create a destination rectangle for the images
        SDL_Rect tmp;
        tmp.x= 0;
        tmp.y = 0;
        tmp.w = 1920;
        tmp.h = 1080; 
            
        //get current time
        curT = chrono::high_resolution_clock::now();
        //get the difference of the current time from the last time the screen was updated
        diff = chrono::duration_cast<chrono::milliseconds>(curT - prevT).count();
        if (diff > TPF)
        {
            //check for keyboard input
            this->checkForInput();
            
            //clear the screen
            SDL_RenderClear(this->renderer);
            
            //for every texture in the imageArray
            for (int i = 0; i < imLength; i++)
            {
                tmp.x = tmp.x + 20;
                tmp.y = tmp.y + 20;
                // Copy the texture on the renderer
                SDL_RenderCopy(this->renderer, this->imageArray[i], NULL, &tmp);
                // Update the window surface (show the renderer)
                SDL_RenderPresent(this->renderer);
            }
            
            prevT = curT;
            
            //add to the current level time
            this->curTime+=diff;
        }
        if (this->curTime > 4000)
        {
            this->setLevelPlaying(false);
        }
    }
    //destroy images in memory to free up space and avoid leaks
    this->destroyImageArrayFromMemory();
    
    return this->getLevelWon();
}

void level::checkForInput()
{
    cout << "inside checkforinput\n";
    //create an empty event
    //SDL_Event event;
    //loop through all events in the queue
    while (SDL_PollEvent(&event))
    {
        cout << "inside while loop\n";
        switch(event.type)
        {
            //cout << "inside switch\n";
            //a keyboard button is pressed down
            case SDL_KEYDOWN:
                cout << "inside case\n";
                //if it is escape key
                if (event.key.keysym.sym == SDLK_ESCAPE)
                {
                    cout << "Escape key pressed" << endl;
                    this->setLevelPlaying(false);
                }
                else if (event.key.keysym.sym == SDLK_q)
                {
                    cout << "Q key pressed" << endl;
                }
                continue;
            default:
                cout << "unhandled key pressed\n";
        }
    }
}

bool level::checkSDLError(bool c, const char* s)
{
    if (c == 0)
    {
         std::cout << s << " " << SDL_GetError() << endl;
         SDL_Quit();
         return 0;
     }
     return 1;
}

我同时安装了SDL2和SDL2Image。我的makefile是否有问题,这就是为什么我可以在这个简单的示例中使用SDLImage,但不能在更复杂的程序中使用的原因?我还有另一个raspberry pi,其中示例和游戏的makefile都能正常工作。

t3psigkw

t3psigkw1#

当您 * 编译 * .cc [到.o ]时,您没有在makefile中将-I传递到c++
您只传递用于 link.o文件的c++行上的标志。
其中一个.o目标的c++命令也需要sdl2-config
那是你的当务之急不过...
当您这样做时:sdl2-config --cflags,它[部分]产生(例如)-I/usr/local/include/SDL2,因此如果它产生.cc,则源文件.cc将工作:#include <SDL.h> .
但是,* 您的 * .cc文件:#include <SDL2/SDL.h> .
这可能不起作用,因为它位于不同的目录级别[除非添加-I/usr/local/include,这是次优的,因为您要硬连接路径]。

  • 如果 * 它起作用,那是因为编译器假定/usr/local/include.h文件路径的 * 默认 * 部分
    更新日期:

请原谅我不太擅长编译。我试着在一些不同的地方添加-I/usr/local/include/SDL2/SDL.h,但没有改变任何东西。你能为我拼得更清楚一点吗?
您 * 不 * 希望:-I/usr/local/include/SDL2/SDL.h它指向一个 * 文件 *。
您需要:-I/usr/local/include/SDL2它指向 * 目录 *。
但是,你应该做两件事:(1)修复makefile,(2)更改level.cc中的#include指令以使其兼容
下面是我对makefile的调整:

OBJS += frogmain.o
OBJS += game.o
OBJS += level.o
OBJS += sprite.o
OBJS += actor.o
OBJS += vector.o

SDLCFG := sdl2-config

CPLSDL = $(shell $(SDLCFG) --cflags)

LIBSDL = $(shell $(SDLCFG) --libs)
LIBSDL += -lSDL2_image

COPTS += -std=c++0x
COPTS += -Wall
COPTS += -Werror
COPTS += -pedantic

FrogGame: $(OBJS)
    g++ -o FrogGame $(OBJS) $(LIBSDL)

frogmain.o: frogmain.cc game.hh level.hh sprite.hh vector.hh
    g++ -c $(COPTS) frogmain.cc

game.o: game.cc level.hh sprite.hh actor.hh vector.hh
    g++ -c $(COPTS) game.cc

level.o: level.cc sprite.hh actor.hh vector.hh
    g++ -c $(COPTS) $(CPLSDL) level.cc

actor.o: actor.cc vector.hh
    g++ -c $(COPTS) actor.cc

sprite.o: sprite.cc vector.hh
    g++ -c $(COPTS) sprite.cc

vector.o: vector.cc
    g++ -c $(COPTS) vector.cc

clean:
    rm -f $(OBJS) FrogGame

如果你复制粘贴的话,TAB将会变成四个空格[因为代码块在SO是如何格式化的],所以你需要手动编辑来改变它(比如makeTAB的开头很挑剔)。
level.cc中,您使用的不是两个#include指令:

#include <SDL2/SDL.h>
#include <SDL2/SDL_Image.h>

您需要:

#include <SDL.h>
#include <SDL_Image.h>
qnyhuwrf

qnyhuwrf2#

sudo pacman -S sdl2_image可以修复此错误,请参阅SDL/SDL_image.h: No such file or directory

相关问题