【问题标题】:SDL 2.0 - Rendering: PNG file doesn't renderSDL 2.0 - 渲染:PNG 文件不渲染
【发布时间】:2014-10-06 08:38:17
【问题描述】:

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

  • GUI_Engine
  • GUI_Element
  • GUI_Panel
  • GUI_Window

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

GUI_Engine 存储指向 GUI_Element 的指针并加载各种 PNG 文件以供所有 GUI_Element 使用。这些 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 以外的其他内容,则会呈现顶部和底部栏。

注意:

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

它是这样的:

编辑:这是我的 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);
}

有人请帮帮我!

【问题讨论】:

  • 听起来这两个纹理/PNG 有问题。 1. 尝试在其他地方渲染纹理一次(比如在 window_top_left 的位置。2. 检查 PNG 是否正确。alpha 有什么奇怪的地方吗? 3. 尝试将您知道的另一个 PNG 复制到 window_top 的 PNG 中和 window_bottom。
  • 是的,实际上,我已经完成了所有这三个操作。似乎问题出在 指针 上,因为如果我将它们加载为 SDL_Texture* 而不是 SDL_Texture**,文件呈现正常。诡异的。但为什么呢?
  • 好的,所以我刚刚添加了纹理加载代码。不过,它确实有效。
  • 你为什么要使用 SDL_Texture**?为什么需要指向指针的指针?为什么不简单地传递一个简单的指针?现在这纯粹是猜测,因为我看不到您调用set_texture_pointer 的代码:如果您通过执行ptr = &amp;texture_pool[i] 之类的操作获得SDL_Texture**,然后您继续向texture_pool 添加其他纹理(我假设是一个向量),当texture_pool 在内部调整大小时,指针可能会四处移动并且您的 SDL_Texture** 不再有效。
  • @Cinch:SDL_Texture 是对象,SDL 正在向您返回指向该对象的指针。无需存储指向此指针的指针。 SDL 在内部存储对象并为您提供指向它们的指针。或许可以查看关于 c 指针的教程:tutorialspoint.com/cprogramming/c_pointers.htm。它们有时会很棘手。

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


【解决方案1】:

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

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

    1. 不需要额外的间接级别 - SDL 无论如何都会返回指向资源的指针,因此我只需要传递常规指针值即可解决问题。
    1. 第二种但不太可靠的解决方案是在插入之前为 std::vector 保留空间,但是一旦向量复制自身,这将不可避免地再次使双指针无效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-28
    • 1970-01-01
    • 2015-12-10
    • 2013-06-06
    • 2019-07-08
    相关资源
    最近更新 更多