SDL 2.0 - 渲染:PNG文件无法渲染

时间:2014-08-13 05:12:09

标签: c++ graphics png sdl sdl-2

我目前正在为自己的个人视频游戏项目开发内部GUI,目前我已经完成了创建基本框架的工作。它由以下类组成:

  • GUI_Engine
  • GUI_Element
  • GUI_Panel
  • GUI_Window

GUI_Element是我将使用我的框架创建的所有GUI类的抽象基类,其子类是GUI_Panel。 GUI_Panel的子节点是GUI_Window。

GUI_Engine存储指向GUI_Element的指针,并加载要由所有GUI_Element使用的各种PNG文件。这些PNG文件存储在SpritePool中,这是一个简单的双向量,可以存储SDL_Texture和std :: string。字符串是PNG文件名。

我目前有两个PNG文件无法使用 void GUI_Window :: render()函数,“window_top”和“window_bottom”中的以下代码正确呈现。这些16x16文件是用于渲染窗口顶部和底部边框的图块;然而,它们是唯一两个无法正确渲染的纹理。

这是GUI_Element的代码:

/*
Class:      GUI_Element
Purpose:    -To provide an ABSTRACT base class for all the GUI elements within the framework.

Notes:      >The class already holds basic functions for hot, cold, select, and deslect.
             Function pointers are going to use to provide callback/like functionality.

*/

#ifndef GUI_ELEMENT_H
#define GUI_ELEMENT_H

#include "globalvar.h"
#include "Input.h"
#include "SpritePool.h"

class GUI_Element
{
public:
    GUI_Element() {}
    GUI_Element(SpritePool gui_skin, int x, int y, int w, int h, bool visible,     GUI_Element* parent);
    virtual ~GUI_Element();

    //set functions
    void set_texture_ptr(SDL_Texture** texture) {texture_ptr = texture;}
    void set_parent_element(GUI_Element* parent);
    void set_frame(int x, int y, int w, int h);
    void set_offset_x(int i) {offset_x = i;}
    void set_offset_y(int i) {offset_y = i;}
    void set_x(int i) {frame.x = i;}
    void set_y(int i) {frame.y = i;}
    void set_w(int i) {frame.w = i;}
    void set_h(int i) {frame.h = i;}
    void set_visible(bool b);
    void set_hot(bool b);
    void set_selected(bool b);

    //get functions
    SDL_Texture** get_texture_ptr() {return texture_ptr;}
    GUI_Element* get_parent_element() {return parent_element;}
    SDL_Rect* get_frame() {return &frame;}
    int get_offset_x() {return offset_x;}
    int get_offset_y() {return offset_y;}
    int get_x() {return frame.x;}
    int get_y() {return frame.y;}
    int get_w() {return frame.w;}
    int get_h() {return frame.h;}

    //is_property functions
    bool is_visible() {return visible;}
    bool is_hot() {return hot;}
    bool is_selected() {return selected;}

    //on_action functions
    virtual void on_hot() = 0;
    virtual void on_cold() = 0;
    virtual void on_select() = 0;
    virtual void on_deselect() = 0;

    //render/update/check input functions
    virtual void render() = 0;
    virtual void update() = 0;
    virtual void check(Input &input) = 0;

protected:
    int offset_x, offset_y;

    SDL_Texture** texture_ptr;

    GUI_Element* parent_element;

    SDL_Rect frame;

    bool visible;
    bool hot;
    bool selected;

    void (*func_hot) ();
    void (*func_select) ();
    void (*func_cold) ();
    void (*func_deselect) ();


private:
};

这是GUI_Window的代码:

#ifndef GUI_WINDOW_H
#define GUI_WINDOW_H

#include "GUI_Panel.h"

class GUI_Window : public GUI_Panel
{
public:
    GUI_Window(SpritePool gui_skin, int x, int y, int w, int h, bool visible, std::string str);
    virtual ~GUI_Window();

    void set_name(std::string str) {name = str;}
    void set_menubar_properties(bool minimize, bool pin, bool exit);
    void set_border_visible(bool b);
    void set_bg_visible(bool b);

    std::string get_name() {return name;}
    bool get_minimize_visible() {return minimize_visible;}
    bool get_pin_visible() {return pin_visible;}
    bool get_exit_visible() {return exit_visible;}
    bool get_border_visible() {return border_visible;}
    bool get_bg_visible() {return bg_visible;}

    virtual void on_hot();
    virtual void on_cold();
    virtual void on_select();
    virtual void on_deselect();

    //render/update/check input functions
    virtual void render();
    virtual void update();
    virtual void check(Input &input);

protected:
    std::string name;

    bool minimize_visible;
    bool pin_visible;
    bool exit_visible;
    bool border_visible;
    bool bg_visible;

    SDL_Rect tile_frame;

    SDL_Texture** window_top;
    SDL_Texture** window_bottom;
    SDL_Texture** window_left;
    SDL_Texture** window_right;
    SDL_Texture** window_topleft;
    SDL_Texture** window_topright;
    SDL_Texture** window_bottomleft;
    SDL_Texture** window_bottomright;
    SDL_Texture** window_minimize;
    SDL_Texture** window_pin;
    SDL_Texture** window_exit;
    SDL_Texture** gui_bg;

private:
};

#endif // GUI_WINDOW_H

这里是GUI_Window :: render()的代码:

void GUI_Window::render()
{
if (visible)
{
    if (bg_visible)
    {
        SDL_RenderCopy(g_renderer, *gui_bg, NULL, &frame);
    }

    if (border_visible)
    {
        tile_frame.x = frame.x;
        tile_frame.y = frame.y;
        tile_frame.w = 16;
        tile_frame.h = 16;

        SDL_RenderCopy(g_renderer, *window_topleft, NULL, &tile_frame);
        tile_frame.y = frame.y;

        while (tile_frame.x < (frame.x + frame.w - 32))
        {
            SDL_RenderCopy(g_renderer, *window_top, NULL, &tile_frame);
            tile_frame.x += 16;
        }

        tile_frame.x += 16;
        SDL_RenderCopy(g_renderer, *window_topright, NULL, &tile_frame);

        if (window_top == NULL)
            std::cout << "oh well" << std::endl;

        while (tile_frame.y < (frame.y + frame.h - 16))
        {
            tile_frame.y += 16;
            SDL_RenderCopy(g_renderer, *window_right, NULL, &tile_frame);
        }

        SDL_RenderCopy(g_renderer, *window_bottomright, NULL, &tile_frame);

        while (tile_frame.x > frame.x + 16)
        {
            tile_frame.x -= 16;
            SDL_RenderCopy(g_renderer, *window_bottom, NULL, &tile_frame);
        }

        tile_frame.x -= 16;
        SDL_RenderCopy(g_renderer, *window_bottomleft, NULL, &tile_frame);

        while (tile_frame.y > frame.y + 16)
        {
            tile_frame.y -= 16;
            SDL_RenderCopy(g_renderer, *window_left, NULL, &tile_frame);
        }
    }

    if (exit_visible)
    {
        tile_frame.x = frame.x + frame.w - 16;
        tile_frame.y = frame.y;
        SDL_RenderCopy(g_renderer, *window_exit, NULL, &tile_frame);
    }

    if (pin_visible)
    {
        tile_frame.x = frame.x + frame.w - 32;
        tile_frame.y = frame.y;
        SDL_RenderCopy(g_renderer, *window_pin, NULL, &tile_frame);
    }

    if (minimize_visible)
    {
        tile_frame.x = frame.x + frame.w - 48;
        tile_frame.y = frame.y;
        SDL_RenderCopy(g_renderer, *window_minimize, NULL, &tile_frame);
    }
}
}

我检查了以下内容:

  1. GUI_Engine正确加载所有PNG文件。没有SDL_Texture *为NULL;
  2. GUI_Window应该正确地将所有SDL_Texture *加载到SDL_Texture **中。这些指针都不是NULL。
  3. GUI_Window :: render()中的循环逻辑正确运行。
  4. 奇怪的是,如果将SDL_Texture **更改为window_top和window_bottom之外的其他内容,则会显示顶部和底部栏。
  5. 注意:

    SDL_Texture **名称与PNG文件完全相同。

    这是它的样子:

    The top and bottom border texture, window_top and window_bottom, are the only ones that are not rendering. Could it be due to a PNG naming conflict?

    编辑:这是我的SpritePool类中的纹理加载代码:

    void SpritePool::load_texture(std::string path)
    {
    SDL_Texture* loaded_texture = NULL;
    
    SDL_Surface* loaded_surface = NULL;
    loaded_surface = IMG_Load(path.c_str());
    if (loaded_surface == NULL)
        std::cout << path << " unable to be loaded!" << std::endl;
    else
    {
        loaded_texture = SDL_CreateTextureFromSurface(g_renderer, loaded_surface);
        if (loaded_texture == NULL)
            std::cout << path << " unable to be converted to SDL_Texture*!" << std::endl;
        else
            std::cout << path << " loaded!" << std::endl;
    }
    
    SDL_FreeSurface(loaded_surface);
    
    texture_pool.push_back(loaded_texture);
    texture_names.push_back(path);
    }
    

    有人请帮助我!

1 个答案:

答案 0 :(得分:0)

查看我的代码后,通过将SDL_Texture **转换为SDL_Texture *来解决问题。

编辑:经过大约一年的编程,我现在可以说这个问题的错误在于我使用带有std :: vector的SDL_Texture **。虽然我的矢量只有常规指针,但我发出了双指针。但是,当std :: vector调整自身大小时,它会将其内部结构复制到内存中的另一个空间,使双指针无效。

    1. 间接的附加级别是不需要的 - SDL无论如何返回指向资源的指针,所以我只需要传递常规指针值,这就解决了问题。
    1. 第二个但不太稳健的解决方案是在插入之前为std :: vector预留空间,但是一旦向量复制自身,这将不可避免地再次使双指针无效。