Programming Question


zaephen

Member
Joined
Apr 3, 2010
Messages
126
Age
52
Location
KY, USA
I've been out of the programming bit for a good while now. I'm trying to get back into it to contribute something to this community and hardware that I love. I'm not an expert coder by any means but I've already hit a snag. It's probably something simple that I'm just overlooking. If one of you more experienced coders could browse over the code I've written below and see if you can spot my problem/s I'd really appreciate it ;) .

Basically, what this code does it display the frames per second (which is about 150, seems a little low to me, PC is getting about 1300), the glob_x & y coords and dst.x & y coords and a little sprite that I can move around the screen. Now, everything works perfectly but at random (and I mean random, it happens at a different time/place on the screen each time) the glob_x or y coord will jump from say, 145 to something like 222334456.3322 or something and the corresponding dst variable will jump to something like 10000. Before I put the coords on the screen, the sprite would just disappear. I figured it really wasn't it was just going off the screen, which is the case. My question is why?
Sorry the code snippit is so long but I wanted to include it all in hopes someone could find the problem.
Any help is much appreciated.

Code:
/*-----------------------------------------------------------------------------
  Include Files
  ---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <unistd.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>

/*-----------------------------------------------------------------------------
  Defines
  ---------------------------------------------------------------------------*/
#define SCREEN_WIDTH		320
#define SCREEN_HEIGHT		240
#define SCREEN_BIT_DEPTH	16

/* Defines for the WIZ controls. */
#define WIZ_UP				0
#define WIZ_UP_LEFT			1
#define WIZ_LEFT			2
#define WIZ_DOWN_LEFT		3
#define WIZ_DOWN			4
#define WIZ_DOWN_RIGHT		5
#define WIZ_RIGHT			6
#define WIZ_UP_RIGHT		7
#define WIZ_MENU			8
#define WIZ_SELECT			9
#define WIZ_L				10
#define WIZ_R				11
#define WIZ_A				12
#define WIZ_B				13
#define WIZ_X				14
#define WIZ_Y				15
#define WIZ_VOL_UP			16
#define WIZ_VOL_DOWN		17

/*-----------------------------------------------------------------------------
  Type Definitions
  ---------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
  Globals
  ---------------------------------------------------------------------------*/
SDL_Surface*	screen				= NULL;
SDL_Surface*	text				= NULL;
SDL_Event		event;
SDL_Joystick*	joystick;
TTF_Font*		default_font		= NULL;
FILE*			logfile;
Uint8*			keys;
Uint32			FPS					= 0;
Uint32			frame_count			= 0;
Uint32			tick1, tick2;
float			time_delta			= 0.0f;
SDL_bool		show_fps			= SDL_TRUE;

/* Temp. */
SDL_Surface*	player				= NULL;
float           glob_x              = 50.0f;
float           glob_y              = 50.0f;
Uint8           velocity            = 60;
/* End Temp. */

/*-----------------------------------------------------------------------------
  LoadImage()
  Loads an image.
  ---------------------------------------------------------------------------*/
SDL_Surface* LoadImage(char* file_name) {
    /* Local variables. */
    SDL_Surface* loaded_image = NULL;
    SDL_Surface* optimized_image = NULL;

    /* Load the image. */
    loaded_image = IMG_Load(file_name);

    /* Create an optimized image if nothing went wrong in loading the
       image. */
    if (loaded_image != NULL) {
		optimized_image = SDL_DisplayFormat(loaded_image);
		Uint32 colorkey = SDL_MapRGB(optimized_image->format, 255, 0, 255);
		/* Set all pixels of colorkey color to be transparent. */
		SDL_SetColorKey(optimized_image, SDL_SRCCOLORKEY, colorkey);
		/* Free the original image. */
		SDL_FreeSurface(loaded_image);
    }

    /* Return the optimized image. */
    return optimized_image;
}

/*-----------------------------------------------------------------------------
  RenderText()
  Renders text to a surface for rendering on the screen.
  ---------------------------------------------------------------------------*/
SDL_bool RenderText(TTF_Font* font, Uint32 x, Uint32 y, SDL_Surface* src,
					SDL_Surface* dst, char* text, SDL_Color color) {
	/* Local variables. */
    SDL_Rect position;

    position.x = x;
    position.y = y;

    src = TTF_RenderText_Solid(font, text, color);
    SDL_BlitSurface(src, NULL, screen, &position);

    SDL_FreeSurface(src);
    src = NULL;

    return SDL_TRUE;
}

/*-----------------------------------------------------------------------------
  Initialize()
  Set all data for the engine.
  ---------------------------------------------------------------------------*/
SDL_bool Initialize(void) {
	/* Initialize SDL's subsystems - in this case, only video. */
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
		fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
		exit(1);
	}

	/* Register SDL_Quit to be called at exit and make sure things are cleaned
	   up when we quit. */
    atexit(SDL_Quit);

    /* Attempt to create a 320x240 window with 32bit pixels. */
    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BIT_DEPTH,
							  SDL_SWSURFACE | SDL_FULLSCREEN);

    /* If screen wasn't set, return error. */
    if (screen == NULL) {
		fprintf(stderr, "Unable to set 320x240 video: %s\n", SDL_GetError());
		exit(1);
    }

    /* Set the window caption. */
    SDL_WM_SetCaption("Frantic", NULL);

    /* Initialize SDL_ttf. */
    if (TTF_Init() == -1) {
		fprintf(stderr, "Could not initialize TTF!\n");
		return SDL_FALSE;
    }

    /* Open the default program font. */
    default_font = TTF_OpenFont("04b03.ttf", 8);
    if (default_font == NULL) {
		fprintf(stderr, "Error loading default font!\n");
		return SDL_FALSE;
    }

	/* Initialize log file. */
	logfile = fopen("log.txt", "w");

	/* Open joystick control. */
	joystick = SDL_JoystickOpen(0);
	SDL_JoystickEventState(SDL_IGNORE);

    /* Hide the mouse cursor. */
    SDL_ShowCursor(SDL_FALSE);

    /* Get the keyboard state for user input. */
    keys = SDL_GetKeyState(NULL);

	/* Seed the random number generator. */
	srand(SDL_GetTicks());

    /* Get ticks before entering the main loop. */
    tick1 = SDL_GetTicks();

    /* Temp. */
    /* Load the player image. */
	player = SDL_LoadBMP("player.bmp");
    //player = LoadImage("player.png");
    if (player == NULL) {
		printf("Error loading player image!\n");
		return SDL_FALSE;
    }
    /* End Temp. */

	/* Return success. */
	return SDL_TRUE;
}

/*-----------------------------------------------------------------------------
  Render()
  Renders to the screen.
  ---------------------------------------------------------------------------*/
void Render(void) {
	/* Local variables. */
    SDL_Color text_color = {255, 255, 255};
    char sbuf[128];
    /* Temp. */
    SDL_Rect src = {0, 0, 15, 16};
    SDL_Rect dst = {0, 0, 15, 16};
    /* End Temp. */

    /* Lock the screen surface if needed. */
    if (SDL_MUSTLOCK(screen)) {
		if (SDL_LockSurface(screen) < 0) {
			fprintf(stderr, "Could not lock the screen surface!\n");
			return;
		}
    }

    /* Draw here. */
    /* Clear the screen to black. */
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));

    /* Render the player. */
	dst.x = glob_x;
	dst.y = glob_y;
	SDL_BlitSurface(player, &src, screen, &dst);

	/* Test blit coords. */
	/*fprintf(logfile, "glob_x: %f\t", glob_x);
	fprintf(logfile, "dst.x: %d\t", dst.x);
	fprintf(logfile, "glob_y: %f\t", glob_y);
	fprintf(logfile, "dst.y: %d\r", dst.y);
*/
	/* Show FPS. */
	if (show_fps == SDL_TRUE) {
		sprintf(sbuf, "FPS = %d", FPS);
		RenderText(default_font, 0, 0, text, screen, sbuf, text_color);
	}

	sprintf(sbuf, "glob_x: %f", glob_x);
	RenderText(default_font, 0, 8, text, screen, sbuf, text_color);
	sprintf(sbuf, "dst.x: %d", dst.x);
	RenderText(default_font, 120, 8, text, screen, sbuf, text_color);
	sprintf(sbuf, "glob_y: %f", glob_y);
	RenderText(default_font, 0, 16, text, screen, sbuf, text_color);
	sprintf(sbuf, "dst.y: %d", dst.y);
	RenderText(default_font, 120, 16, text, screen, sbuf, text_color);

	/* Unlock if needed. */
	if (SDL_MUSTLOCK(screen))
		SDL_UnlockSurface(screen);

	/* Tell SDL to update the whole screen. */
	SDL_UpdateRect(screen, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}

/*-----------------------------------------------------------------------------
  CleanUp()
  Free memory and prepare to quit.
  ---------------------------------------------------------------------------*/
void CleanUp(void) {
	fclose(logfile);
	SDL_ShowCursor(SDL_TRUE);
	if (text != NULL)
		SDL_FreeSurface(text);
	TTF_CloseFont(default_font);
	TTF_Quit();
	SDL_JoystickClose(joystick);
    if (player != NULL)
		SDL_FreeSurface(player);
	SDL_Quit();
}

/*-----------------------------------------------------------------------------
  main()
  Program execution begins here.
  ---------------------------------------------------------------------------*/
int main(int argc, char *argv[]) {
	/* Local variables. */
    SDL_Event event;
    SDL_bool loop = SDL_TRUE;
    Uint32 tick_dif = 0;

    /* Initialize. */
	if (Initialize() != SDL_TRUE) {
		fprintf(stderr, "Initialize() failed!\n");
		return SDL_FALSE;
	}

    /* Main loop. */
    while (loop) {
		/* Get ticks first thing every loop. */
		tick2 = SDL_GetTicks();
		/* Calculate the time pasted since getting ticks last. */
		time_delta = (tick2 - tick1);
		/* Very sloppy FPS code I'm sure ;o). */
		tick_dif += time_delta;
		if (tick_dif > 1000) {
			FPS = frame_count;
			tick_dif = 0;
			frame_count = 0;
		}
		time_delta = time_delta * 0.001f;
		/* This will be the old ticks next loop. */
		tick1 = tick2;

		/* Render stuff. */
		Render();

		/* Process user input. */
		SDL_JoystickUpdate();
		if (SDL_JoystickGetButton(joystick, WIZ_MENU)
			&& SDL_JoystickGetButton(joystick, WIZ_SELECT)) {
			loop = 0;
		}
		if (SDL_JoystickGetButton(joystick, WIZ_A)) {
			glob_x = 50;
			glob_y = 50;
		}

        if (SDL_JoystickGetButton(joystick, WIZ_UP))
			glob_y -= time_delta * velocity;
		if (SDL_JoystickGetButton(joystick, WIZ_LEFT))
			glob_x -= time_delta * velocity;
		if (SDL_JoystickGetButton(joystick, WIZ_DOWN))
			glob_y += time_delta * velocity;
		if (SDL_JoystickGetButton(joystick, WIZ_RIGHT))
			glob_x += time_delta * velocity;

		if (SDL_JoystickGetButton(joystick, WIZ_UP_LEFT)) {
			glob_y -= time_delta * velocity;
			glob_x -= time_delta * velocity;
		}
		if (SDL_JoystickGetButton(joystick, WIZ_DOWN_LEFT)) {
			glob_x -= time_delta * velocity;
			glob_y += time_delta * velocity;
		}
		if (SDL_JoystickGetButton(joystick, WIZ_DOWN_RIGHT)) {
			glob_y += time_delta * velocity;
			glob_x += time_delta * velocity;
		}
		if (SDL_JoystickGetButton(joystick, WIZ_UP_RIGHT)) {
			glob_x += time_delta * velocity;
			glob_y -= time_delta * velocity;
		}

		/* Event processing. */
		while (SDL_PollEvent(&event)) {
			switch (event.type) {
   			    /* If a key was pressed. */
				case SDL_KEYDOWN:
					switch (event.key.keysym.sym) {
						case SDLK_ESCAPE:
							loop = 0;
							break;
						case SDLK_F1:
							if (show_fps == SDL_TRUE)
								show_fps = SDL_FALSE;
							else
								show_fps = SDL_TRUE;
							break;
						default:
							break;
					}
				default:
					break;
			}
		}

		/* Update the screen. */
		if (SDL_Flip(screen) == -1) {
			return 1;
		}

		/* Increment the FPS counter. */
		frame_count++;
    }

    /* Clean up before exiting! */
	CleanUp();

	/* Return to the GP2X WIZ menu. */
	chdir("/usr/gp2x");
	execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL);

    /* Exit program. */
    return SDL_TRUE;
}
 
Hmm, I have not spotted the problem, but the only variable that glob_x/y seem to depend on is time_delta, I would investigate that and the tick1/2 variables that it depends on. If you trace back that huge glob_x: ( 222334456.3322 / 60 ) * 1000 = 3705574272. This, or a value close to it has somehow come out of (tick2-tick1). This can only be if for some reason tick2 was smaller than tick1 at the time of the computation (integer overflow). Investigate tick1/2 is what I'm saying :)

Also I noticed that you mix a lot of numeric types in your code: Uint32, Uint8, float, Sint16 (dst.x/y)... you have to be careful to avoid overflows there as well!
(BTW: dst.x follows glob_x, so it is no wonder that it overflows as soon as glob_x >= 32768)
 
Yeah, this is generally bad voodoo, mixing types without comprehension. dst.x is a 16 bit integer, glob_x is float (24 bit?), the two are *not* the same type of storage and produce incompatible values when not properly assigned to each other ..
 
torpor said:
Yeah, this is generally bad voodoo, mixing types without comprehension. dst.x is a 16 bit integer, glob_x is float (24 bit?), the two are *not* the same type of storage and produce incompatible values when not properly assigned to each other ..
Right. But the way I was using them I thought it would be okay. The float in necessary to hold the .xxxx increment and of course the integer is the whole amount to move.


Reo said:
You're a commenting master!
Er, I think that's a compliment, I'll take that as one anyway ;) . Seriously, I think it makes things easier in cases like this where someone else is looking at the code. I mean, I know what most of it does easily as I wrote it but it really helps someone else to have the comments.
 
Last edited by a moderator:
When the machine executes this code from main(), tick1 is not initialized yet.

Code:
                /* Calculate the time pasted since getting ticks last. */
                time_delta = (tick2 - tick1);
 
Rodolfo said:
When the machine executes this code from main(), tick1 is not initialized yet.

Code:
                /* Calculate the time pasted since getting ticks last. */
                time_delta = (tick2 - tick1);
I believe it is. The first thing main() does is call Initialize() in which I have "tick1 = SDL_GetTicks();".

The previous replies were spot on. I used my logfile to check the values of tick1 & tick2. Sure enough, the value of tick1 when the sprite disappears is less than... er, or greater than (can remember which way it went) tick2! Now, can anyone explain to me how that can be? Tick2 is taken at the beginning of the loop and tick1 afterward. How in the hell can can it get ahead of it?
I fixed it basically by putting in a check to see if the value of tick1 is less than (I think) tick2. Strange.
 
Last edited by a moderator:
I tried this on my PC and GP2X (sorry no wiz - 85 FPS) and I haven't seen the error after trying for about 5 minutes.

Looks like the wiz has a broken SDL_GetTicks
 
Parkydr said:
I tried this on my PC and GP2X (sorry no wiz - 85 FPS) and I haven't seen the error after trying for about 5 minutes.

Looks like the wiz has a broken SDL_GetTicks
actually the RTC implementation is broken thus SDL_GetTicks might be broken, yes.

there's a workaround for this problem, notaz posted it using an alternative timer:
notaz highspeed timer

*edit* removed some actually ;)
 
Last edited by a moderator:
crow_riot said:
Parkydr said:
I tried this on my PC and GP2X (sorry no wiz - 85 FPS) and I haven't seen the error after trying for about 5 minutes.

Looks like the wiz has a broken SDL_GetTicks
actually the RTC implementation is broken thus SDL_GetTicks might be broken, yes.

there's a workaround for this problem, notaz posted it using an alternative timer:
notaz highspeed timer

*edit* removed some actually ;)

I can also confirm the SDL_GetTicks is not very accurate, also be aware SDL_Delay will also delay longer than expected.
 
Last edited by a moderator:
torpor said:

He wasn't doing anything wrong. Taking a sub-pixel floating point value and assigning to 16-bit integer for screen coordinates is perfectly acceptable; there isn't anything wrong with relying on the truncation performed. Data representation (like your original post talked about) doesn't come into play. How do you think he lacked comprehension and what exactly do you think he should have done instead?
 
Last edited by a moderator:
Thanks for all the answers guys :) .
I didn't think there was anything wrong with truncating the decimal from the float, it seemed to work perfectly on my PC, always has in the past anyway. I've done a little casting in the past but not much. It truly seems the SDL_GetTicks() is broken on the WiZ as it works flawlessly on my PC both in WinXP(at work) and Linux(home).
I tried a bit of the alternate timer posted but couldn't get it to work. Not sure what I'm doing wrong. Getting:
Code:
"main.c|148|error: 'O_RDWR' undeclared (first use in this function)"
type errors. As stated in the beginning, I'm just an amateur coder. I do it because I really enjoy sitting and writing programs. I'm not all that good at it LOL.
My solution to check the tick2 vs tick1 and see if I actually "went back in time" seems to be working perfectly so I'll stick with that as I understand it.
 
Zaephen said:
Not sure what I'm doing wrong. Getting:
Code:
"main.c|148|error: 'O_RDWR' undeclared (first use in this function)"


Your only missing some headers try adding:
Code:
#include "unistd.h"    
 #include "sys/ioctl.h"
 #include "fcntl.h"
 
Last edited by a moderator:
This is a little tangential, but I recommend coding 2D games for a fixed frame rate that's easily attainable rather than scaling all of your event timing to a maximum frame rate. This will simplify your game and animation logic. It'll also allow you to wait for vsync and save some power (if you manage to find a good way to make the CPU idle while waiting). IMG actually claims that a lower but fixed framerate is more aesthetically pleasing than a higher average but varying one, and it's not really hard to see why this wouldn't be the case. This is for 3D games; I think for 2D games the effect will be much more jarring since the movements are much more discrete.
 
Pickle said:
Zaephen said:
Not sure what I'm doing wrong. Getting:
Code:
"main.c|148|error: 'O_RDWR' undeclared (first use in this function)"


Your only missing some headers try adding:
Code:
#include "unistd.h"    
 #include "sys/ioctl.h"
 #include "fcntl.h"
Now I'm getting:
Code:
main.c|149|error: 'PROT_READ' undeclared (first use in this function)|
 
Last edited by a moderator:
crow_riot said:
try adding

Code:
#include <sys/mman.h>
Thanks Crow, that fixed it :D!
Now could anyone tell me easily what the difference between the value this is giving me vs what I was getting with SDL_GetTicks()?
Just using this with the code I had set up to figure FPS isn't working.
 
Last edited by a moderator:
Zaephen said:
crow_riot said:
try adding

Code:
#include <sys/mman.h>
Thanks Crow, that fixed it :D !
Now could anyone tell me easily what the difference between the value this is giving me vs what I was getting with SDL_GetTicks()?
Just using this with the code I had set up to figure FPS isn't working.[/size][/font]


from http://sdl.beuc.net/sdl.wiki/SDL_GetTicks : SDL_GetTicks Gets the number of milliseconds since SDL library initialization.

whereas ptimer_get_ticks_us returns microseconds. so divide the return value from get_ticks_us by 1000 then you have the same unit.
 
Last edited by a moderator:
Back
Top