• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Kain5056

SDL_Surface to OpenGL texture problem.

10 posts in this topic

Hello. I have a bit of a problem, so a little help from someone more experienced would be appreciated. :-)

 

I've been using SDL for a few months, and have gotten quite good at it and started making my first game. But now I want my game to use hardware accelerated rendering because software rendering won't cut it any more, so I started looking into OpenGL.

 

Since I have some experience in SDL and kind of know what I'm doing with it, but know nothing about OpenGL, I tried to find the simplest way possible to convert my SDL surfaces to OpenGL textures and render them with OpenGL.

 

So I found THIS and THIS from sdltutorials.com

 

Following these instructions, I altered my Initialization and rendering functions from this:

 

bool init()
{
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) return false;

    screen = SDL_SetVideoMode( SCREEN_WIDTH , SCREEN_HEIGHT , BITS_PER_PIXEL , SDL_HWSURFACE | SDL_DOUBLEBUF );
    if( screen == NULL ) return false;
    if( Mix_OpenAudio( 44100 , MIX_DEFAULT_FORMAT , 2 , 512 ) < 0 ) return false;
    SDL_WM_SetCaption( "Test!" , NULL );
    return true;
}

SDL_Surface * load( std::string file )
{
    SDL_Surface * loaded = NULL;
    SDL_Surface * optimized = NULL;
    loaded = IMG_Load( file.c_str() );
    if( loaded != NULL )
    {
        optimized = SDL_DisplayFormatAlpha( loaded );
        SDL_FreeSurface( loaded );
    }
    return optimized;
}

void apply_surface( int x , int y , SDL_Surface * get = NULL , SDL_Surface * give = NULL , SDL_Rect * clips = NULL )
{
    SDL_Rect offsets;

    offsets.x = x;
    offsets.y = y;

    SDL_BlitSurface( get , clips , give , &offsets );
}

void apply_surface( int x , int y , SDL_Surface * get , SDL_Surface * give , int clips_x , int clips_y , int w , int h )
{
    SDL_Rect offsets;

    offsets.x = x;
    offsets.y = y;

    SDL_Rect clips;

    clips.x = clips_x;
    clips.y = clips_y;
    clips.w = w;
    clips.h = h;

    SDL_BlitSurface( get , &clips , give , &offsets );
}

 

 

 

 

...To this:

 

bool init()
{
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) return false;

    SDL_GL_SetAttribute(SDL_GL_RED_SIZE,8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE,8);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16);
    SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,32);
    SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,8);
    SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE,8);
    SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE,8);
    SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE,8);
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS,1);
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,2);

    screen = SDL_SetVideoMode( SCREEN_WIDTH , SCREEN_HEIGHT , BITS_PER_PIXEL , SDL_HWSURFACE | SDL_GL_DOUBLEBUFFER | SDL_OPENGL );

    glClearColor(0, 0, 0, 0);
    glClearDepth(1.0f);
    glViewport(0, 0, SCREEN_WIDTH , SCREEN_HEIGHT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, SCREEN_WIDTH , SCREEN_HEIGHT, 0, 1, -1);
    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_TEXTURE_2D);
    glLoadIdentity();

    if( screen == NULL ) return false;
    if( Mix_OpenAudio( 44100 , MIX_DEFAULT_FORMAT , 2 , 512 ) < 0 ) return false;
    SDL_WM_SetCaption( "OpenGL Test!" , NULL );
    return true;
}

SDL_Surface * load( std::string file )
{
    SDL_Surface * loaded = NULL;
    loaded = IMG_Load( file.c_str() );

    return loaded;
}

void apply_surface( int x , int y , SDL_Surface * get = NULL )
{
    GLuint textureID = 0;

    glGenTextures(1, &textureID);

    glBindTexture(GL_TEXTURE_2D, textureID);

    int Mode = GL_RGBA;

    glTexImage2D(GL_TEXTURE_2D, 0, Mode, get->w, get->h, 0, Mode, GL_UNSIGNED_BYTE, get->pixels);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glBindTexture(GL_TEXTURE_2D, textureID);

    glBegin(GL_QUADS);

        glTexCoord2f(0, 0);
        glVertex2f(x, y);

        glTexCoord2f(1, 0);
        glVertex2f(x+get->w, y);

        glTexCoord2f(1, 1);
        glVertex2f(x+get->w, y+get->h);

        glTexCoord2f(0, 1);
        glVertex2f(x, y+get->h);
    glEnd();
    glDeleteTextures(1, &textureID);
    glDisable(GL_TEXTURE_2D);

    SDL_GL_SwapBuffers();
}

void apply_surface( int x , int y , SDL_Surface * get , int clips_x , int clips_y , int w , int h )
{
    GLuint textureID = 0;
    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_2D, textureID);

    int Mode = GL_RGBA;

    glTexImage2D(GL_TEXTURE_2D, 0, Mode, get->w, get->h, 0, Mode, GL_UNSIGNED_BYTE, get->pixels);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glBindTexture(GL_TEXTURE_2D, textureID);

    int cx = clips_x / get->w;
    int cy = clips_y / get->h;
    int cw = clips_x+w / get->w;
    int ch = clips_y+h / get->h;

    glBegin(GL_QUADS);

        glTexCoord2f(cx, cy);
        glVertex2f(x, y);

        glTexCoord2f(cx+cw, cy);
        glVertex2f(x+get->w, y);

        glTexCoord2f(cx+cw, cy+ch);
        glVertex2f(x+get->w, y+get->h);

        glTexCoord2f(cx, cy+ch);
        glVertex2f(x, y+get->h);
    glEnd();
    glDeleteTextures(1, &textureID);
    glDisable(GL_TEXTURE_2D);

    SDL_GL_SwapBuffers();
}

 

 

 

...But all I see when I run it is a black screen with a few glitchy rectangles flying by diagonally, and the program runs at 4 frames per second.

 

I will not lie, I have absolutely no idea what I'm actually doing, I just want an easy and fast way to have hardware acceleration without having to change too much of my code. I do want to learn how to properly use OpenGL eventually, but not before I at least finish my first game.

 

If someone can offer some advice on what I'm doing wrong, I would really appreciate it. :-)

 

Thank you in advance. :-)

0

Share this post


Link to post
Share on other sites

The last thing you want to do is glGenTextures/glDeleteTextures every frame.

 

1. Move the code that does the glGenTextures/glTexImage2D/glTexParameteri closer to where your textures get loaded. Once you generate a texture, you can release the associated SDL surface.

 

2. When "applying" a surface, cal glBindTexture with the appropriate texture id. That's all you need (other than the glTexCoord2f's).

 

3. Move the code that does the glDeleteTextures somewhere in your shutdown code, or, if you are loading/unloading resources per level, move it to your unload code.

 

edit - in step 1, you'll also need a glBindTexture there as well. That tells OpenGL what texture the following glTex* code applies to.

Edited by Dave Hunt
1

Share this post


Link to post
Share on other sites

Thanks so much for the help. smile.png

I think I will need some more, though. unsure.png

 

I tried this...:

 

SDL_Surface * load( std::string file )
{
    SDL_Surface * loaded = NULL;
    loaded = IMG_Load( file.c_str() );

    return loaded;
}

void texture( SDL_Surface * get )
{
    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_2D, textureID);

    int Mode = GL_RGBA;

    glTexImage2D(GL_TEXTURE_2D, 0, Mode, get->w, get->h, 0, Mode, GL_UNSIGNED_BYTE, get->pixels);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    SDL_FreeSurface( get );
}

void apply_surface( int x , int y , SDL_Surface * get , SDL_Surface * give = NULL , SDL_Rect * clips = NULL )
{
    if( get ) texture( get );

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glBindTexture(GL_TEXTURE_2D, textureID);

    glBegin(GL_QUADS);

        glTexCoord2f(0, 0);
        glVertex2f(x, y);

        glTexCoord2f(1, 0);
        glVertex2f(x+get->w, y);

        glTexCoord2f(1, 1);
        glVertex2f(x+get->w, y+get->h);

        glTexCoord2f(0, 1);
        glVertex2f(x, y+get->h);
    glEnd();

    SDL_GL_SwapBuffers();
}

void apply_surface( int x , int y , SDL_Surface * get , SDL_Surface * give , int clips_x , int clips_y , int w , int h )
{
    if( get ) texture( get );

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glBindTexture(GL_TEXTURE_2D, textureID);

    int cx = clips_x / get->w;
    int cy = clips_y / get->h;
    int cw = clips_x+w / get->w;
    int ch = clips_y+h / get->h;

    glBegin(GL_QUADS);

        glTexCoord2f(cx, cy);
        glVertex2f(x, y);

        glTexCoord2f(cx+cw, cy);
        glVertex2f(x+get->w, y);

        glTexCoord2f(cx+cw, cy+ch);
        glVertex2f(x+get->w, y+get->h);

        glTexCoord2f(cx, cy+ch);
        glVertex2f(x, y+get->h);
    glEnd();

    SDL_GL_SwapBuffers();
}

void clean_up()
{
    if(textureID > 0)
    {
        glDeleteTextures(1, &textureID);
        textureID = 0;
    }
    glDisable(GL_TEXTURE_2D);
}

 

 

...But it returns 3, trying to access the wrong piece of memory I think. wacko.png

0

Share this post


Link to post
Share on other sites

I will not lie, I have absolutely no idea what I'm actually doing, I just want an easy and fast way to have hardware acceleration without having to change too much of my code. I do want to learn how to properly use OpenGL eventually, but not before I at least finish my first game.

This is probably a bad idea. "Hardware acceleration" won't gain you anything unless your code is structured in a hardware friendly manner, much like the fastest racing car is of little use on a pot-holed dirt track.

 

I've been using SDL for a few months, and have gotten quite good at it and started making my first game. But now I want my game to use hardware accelerated rendering because software rendering won't cut it any more, so I started looking into OpenGL.

If you don't have a performance problem, then finish your game as is.

 

If you have a performance problem, then you need to understand where this problem is coming from. Are you sure that it is the graphics? Profiling your game will give you some clues as to where all the time is spent, which might help identify mitigation techniques. Many an experienced programmer has made some terrible guesses at where their bottlenecks were - only thorough, scientific investigation should be trusted before time and effort is invested into "optimising" some area of the code. The other crucial aspect of profiling is that it gives you a benchmark to exceed, some attempts at optimisation can actually slow things down. Better to have results which can be compared with.

 

If rendering is the root cause. one option is to attempt to resolve it in software mode. It is possible that you are doing some things which are not a good idea. For example, are all your sprites using a full alpha channel? If not, don't use SDL_DisplayFormatAlpha() - software alpha blending is much more complex than regular blitting. I'd recommend reading [url="http://www.oreillynet.com/pub/au/1205#Articles"]Bob Pendleton's SDL articles[/url] if you want to stick with vanilla SDL 1.2.

 

Alternatively, there simply might not be enough optimisation options available to you is the time to really replace your existing rendering code with an alternative. You'll need to take time to learn how to use the new API correctly and effectively. If you want simple hardware acceleration, have you considered SFML? It is a popular library which I believe is hardware accelerated by default. The SDL team have been working on a newer version of the API which is more hardware friendly, SDL 1.3/2.0. I am very out of date on the current state of this library, so whether it is suitable for production yet is something you'll need to check. I got the impression a few years ago that the core functionality was reasonably stable on the big platforms. Raw OpenGL remains an option, but requires a much bigger learning curve than using a 2D library with an accelerated backend.

 

If you want to switch APIs, I'd recommend creating a new project or project(s) (or branches in your version control system - you are using version control, right?) which mimics the graphical complexity of your current project. This will give you safe playgrounds in which to experiment with the APIs and get familiar with them.

 

You'll note that whatever approach you take, you're going to have to do some research.

2

Share this post


Link to post
Share on other sites

Thanks for the advice. smile.png

 

I know it is bad practice to do things I do not understand. My game is actually running good, at 190 frames per second at my old Dual-Core PC, but I'm experiencing problems when I try to record a video of it, even with the lightest program I could find, even though I can record games like Minecraft easily. The framerate does not drop, but the movement is extremely choppy, so I thought that a bit of hardware acceleration might help.

 

After I finish this game I will go ahead and learn OpenGL, but for the time being I just want my SDL game to be able to record on video. unsure.png

0

Share this post


Link to post
Share on other sites

That sounds like it could be a completely different problem, hardware accelerating your drawing may not help at all.

 

It is unclear what you mean though. Do you mean that the recorded movement appears choppy when played back? Do you feel that the movement on screen is choppy when being recorded? Or is it actually the input responsiveness that it causing the trouble?

1

Share this post


Link to post
Share on other sites

Choppy when I'm recording, choppier at playback. The controls also become kind of unresponsive when recording, and sometimes the collision detection does not work well. The framerate counter I implemented at the game shows ~110 frames per second when I'm recording.

 

Everything works perfectly when I'm not recording.

 

I know it could be many things, but the first thing that came to my mind is that because SDL uses software acceleration, and the recording software takes a lot out of the system, if I use the graphics card for the game, I would be able to record. I can record any other game I try with no problems.

Edited by Kain5056
0

Share this post


Link to post
Share on other sites

If you're hitting 60FPS you should be able to maintain a smooth experience. Are you sure your frame counting code is correct? Note it is often useful to measure the time spent per frame. FPS is a non-linear measurement, dropping 1 frame a second at 60 FPS is very different from dropping 1 frame a second at 30 FPS.

 

Are you calling SDL_Flip or SDL_UpdateRect(s) multiple times per frame? I ask only because you appear to be calling SwapBuffers() every time you call "apply_surface". If you were to count each of those a frame, you might have a high FPS but it would take multiple frames to cause the screen to show the next logical frame.

 

Another potential problem is your game logic. You might have it tweaked to run great at the 190 FPS that your development system gets, but perhaps running it on any system that was faster or slower results in a different experience. How are you separating your game logic tick rate from your rendering rate? A simple experiment would be to throw in a short SDL_Delay() at the end of each frame, to simulate a slower machine (without video recording enabled). Does that feel "choppy" too?

1

Share this post


Link to post
Share on other sites

Well, I tested the game at my friends i7 PC and the experience was pretty much the same (except a small issue with the camera movement, but I think I can fix that one), and the counter was at 580 FPS. Still could not record it on video, though, even though it was a lot less choppy there.

 

This is my FPS counter, taken straight from HERE:

 

void timer::loop()
{
    if( ticks + 1000 < SDL_GetTicks() )
    {
        ticks = SDL_GetTicks();
        frame_count = frame;
        frame = 0;
    }

    speed = ( ( SDL_GetTicks() - last_tick ) / 1000.0f ) * 32.0f;
    last_tick = SDL_GetTicks();
    frame++;
}

int timer::get_FPS() { return frame_count; }

 

I use SDL_Flip at the end of every main loop. I just don't know how to properly use SDL_GL_SwapBuffers().

 

I will take another look into my logic. If I can't get the game to work as I want, I think I may just start learning SFML and start over.

0

Share this post


Link to post
Share on other sites

580 FPS means you are running a frame in about a millisecond. Thus, SDL_GetTicks(), with millisecond resolution, is not precise enough to really capture how long each frame lasts. I assume you want to use the "speed" calculation to perform delta time based physics? As your frame rate drops, the delta time for each frame becomes larger, and your game experience could be described as "choppy".

 

Here is a simple program demonstrating the idea:

 
#include <ctime>
#include <cmath>
#include <cstdlib>
#include <sstream>
#include <iostream>
 
#include "SDL.h"
 
int main() {
    std::srand(static_cast<std::time_t>(std::time(nullptr)));
 
    if(SDL_Init(SDL_INIT_VIDEO) < 0) {
        std::cout << "Failed to initialise SDL: " << SDL_GetError() << std::endl;
        return 1;
    }
    std::atexit(&SDL_Quit);
    
    SDL_Surface *screen = SDL_SetVideoMode(400, 400, 0, SDL_SWSURFACE);
    if(!screen) {
        std::cout << "Failed to set video mode: " << SDL_GetError() << std::endl;
        return 1;
    }
 
    float rectX = screen->w * 0.5f;
    float rectY = screen->h * 0.5f;
    const float rectWidth = screen->w * 0.1f;
    const float rectHeight = screen->h * 0.1f;
    const float rectSpeed = 0.1f;
    
    float initialDirection = M_PI * std::rand() / static_cast<float>(RAND_MAX);
    float rectDirectionX = std::cos(initialDirection);
    float rectDirectionY = std::sin(initialDirection);
    
    bool running = true;
    int frames = 0;
    int delay = 0;
    Uint32 fpsTime = SDL_GetTicks();
    Uint32 previous = SDL_GetTicks();
    
    while(running) {
        SDL_Event event;
        while(SDL_PollEvent(&event)) {
            if(event.type == SDL_QUIT) {
                running = false;
            } else if(event.type == SDL_KEYDOWN) {
                if(event.key.keysym.sym == SDLK_ESCAPE) {
                    running = false;
                } else if(event.key.keysym.sym == SDLK_UP) {
                    ++delay;
                } else if(event.key.keysym.sym == SDLK_DOWN) {
                    if(delay > 0) {
                        --delay;
                    }
                }
            }
        }
    
        Uint32 now = SDL_GetTicks();
        Uint32 delta = now - previous;
        previous = now;
        
        rectX += delta * rectSpeed * rectDirectionX;
        rectY += delta * rectSpeed * rectDirectionY;
        if(rectX < 0 || rectX + rectWidth > screen->w) {
            rectDirectionX *= -1;
        }
        if(rectY < 0 || rectY + rectWidth > screen->h) {
            rectDirectionY *= -1;
        }
        
        if(now - fpsTime > 1000) {
            std::stringstream title;
            title << "FPS: " << frames << " (Delay factor: " << delay << ")";
            SDL_WM_SetCaption(title.str().c_str(), nullptr);
            
            fpsTime = now;
            frames = 0;
        }
 
        const Uint32 black = 0;
        SDL_FillRect(screen, nullptr, black);
        SDL_Rect rect {
            static_cast<Sint16>(rectX),
            static_cast<Sint16>(rectY),
            static_cast<Sint16>(rectWidth),
            static_cast<Sint16>(rectHeight)
        };
        const Uint32 colour = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00);
        SDL_FillRect(screen, &rect, colour);
        SDL_Flip(screen);        
        ++frames;
 
        if(delay > 0) {
            SDL_Delay(delay * 10);
        }
    }
    
    return 0;
}

Do you think this code is broadly representative of what your code is trying to do? What kind of results do you get with this code, with and without the video and with various "delay" factors?

 

Have you considered running a fixed time step instead?

 

Again, some of these issues are actually independent of the library you are using, and moving to another library will not necessarily solve them.

0

Share this post


Link to post
Share on other sites

I have actually been following THIS Tutorial, It says it does it this way for everything to move at the same speed no matter how fast or slow the computer is.

 

I might have missed something though. I will try out your code to see what happens, and I will look into variable and fixed time steps (THIS article seems promising on that subject, but I'll look into it some more).

 

Parallel to that I have already started learnig the basics of SFML, just to be sure. smile.png

Edited by Kain5056
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0