OpenGL Exception thrown: read access violation, window was 0xCCCCCCCC - c

I am using the same framework which I had described in the previous question.
I solved it by creating a fresh dll instead of just changing the build type of the project from 'Windows Application (.exe)' to 'DLL (.dll)'.
But now when I use a variable of type GLFWwindow* in my structure and try to write or read. It always causes to pop up write access or read access violation respectively. The exception comes abruptly just as the window starts and then closes, showing the exception.
The exception says the following:-
Exception thrown: read access violation.
window was 0xCCCCCCCC.
It happens in the window.c file of GLFW and it points to the function which tries to read it. I even tried to use pointers to modify the window but still it didn't work.
Here is the code for the framework:- Modified!
window.h
#ifndef LIB_GRAPHICS
#define LIB_GRAPHICS
#ifdef LIB_EXPORTS
#define LIB_EXPORT _declspec(dllexport)
#else
#define LIB_EXPORT _declspec(dllimport)
#endif
#define LIB_FALSE 0
#define LIB_TRUE 1
#define LIB_BeginRender LIB_SetEvents(); LIB_ClearToColor
#define LIB_EndRender LIB_SwapWindowBuffers
#define LIB_CENTER_POSITION 0xCEAAFFEE
/* Define other things... */
typedef const char* LIB_String;
typedef unsigned LIB_Integer;
typedef char LIB_Char;
typedef int LIB_Bool;
/* Define the structures... */
typedef struct LIB_Window LIB_Window;
typedef struct LIB_Color
{
int r;
int g;
int b;
int a;
} LIB_Color;
/* Constructors, destructors and other functions... */
LIB_Bool LIB_EXPORT LIB_Initialize();
void LIB_EXPORT LIB_SetEvents();
void LIB_EXPORT LIB_ClearToColor(const LIB_Color color);
void LIB_EXPORT LIB_SetFrameColor(const LIB_Color color);
LIB_EXPORT LIB_Window* LIB_CreateWindow(const LIB_String title, const int x, const int y, const int width, const int height, const LIB_Bool resizable, const LIB_Bool fullscreen);
void LIB_EXPORT LIB_GetDisplaySize(int *width, int *height);
void LIB_EXPORT LIB_GetWindowFrameSize(LIB_Window* window, int *width, int *height);
void LIB_EXPORT LIB_GetWindowCursorPosition(LIB_Window* window, float *x, float *y);
void LIB_EXPORT LIB_GetWindowPosition(LIB_Window* window, int *x, int *y);
void LIB_EXPORT LIB_GetWindowSize(LIB_Window* window, int *width, int *height);
LIB_String LIB_EXPORT LIB_GetWindowTitle(LIB_Window* window);
LIB_Bool LIB_EXPORT LIB_IsWindowFullScreen(LIB_Window* window);
LIB_Bool LIB_EXPORT LIB_IsWindowOpened(LIB_Window* window);
void LIB_EXPORT LIB_SwapWindowBuffers(LIB_Window* window);
void LIB_EXPORT LIB_SetWindowPosition(LIB_Window* window, const int x, const int y);
void LIB_EXPORT LIB_SetWindowSize(LIB_Window* window, const int width, const int height);
void LIB_EXPORT LIB_SetWindowTitle(LIB_Window * window, const LIB_String title);
void LIB_EXPORT LIB_SetFullScreenState(LIB_Window * window, const LIB_Bool fullscreen);
void LIB_EXPORT LIB_DestroyWindow(LIB_Window* window);
void LIB_EXPORT LIB_Terminate();
#endif /* LIB_GRAPHICS */
window.c
#include "window.h"
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
/* Create the structures... */
struct LIB_Window
{
LIB_String title;
int x;
int y;
int width;
int height;
LIB_Bool fullscreen;
GLFWwindow** window;
};
/* Start the functions here... */
LIB_Bool LIB_Initialize()
{
return (LIB_Bool)glfwInit();
}
void LIB_SetEvents()
{
glfwPollEvents();
}
void LIB_ClearToColor(const LIB_Color color)
{
glClearColor((float)color.r / 255, (float)color.g / 255, (float)color.b / 255, (float)color.a / 255);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
}
void LIB_SetFrameColor(const LIB_Color color)
{
glClearColor((float)color.r / 255, (float)color.g / 255, (float)color.b / 255, (float)color.a / 255);
}
LIB_Window* LIB_CreateWindow(const LIB_String title, int x, int y, const int width, const int height, const LIB_Bool resizable, const LIB_Bool fullscreen)
{
LIB_Window wind;
wind.title = title;
if (x == LIB_CENTER_POSITION)
{
const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
x = (mode->width - width) / 2;
}
wind.x = x;
if (y == LIB_CENTER_POSITION)
{
const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
y = (mode->height - height) / 2;
}
wind.y = y;
wind.width = width;
wind.height = height;
wind.fullscreen = fullscreen;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_RESIZABLE, resizable);
wind.window = NULL;
if (fullscreen == 1)
{
wind.window = (GLFWwindow**)glfwCreateWindow(width, height, title, glfwGetPrimaryMonitor(), NULL);
}
else if (fullscreen == 0)
{
wind.window = (GLFWwindow**)glfwCreateWindow(width, height, title, NULL, NULL);
}
glfwSetWindowPos((GLFWwindow*)wind.window, x, y);
int screen_width, screen_height;
glfwGetFramebufferSize((GLFWwindow*)wind.window, &screen_width, &screen_height);
if (wind.window == NULL)
{
glfwTerminate();
return NULL;
}
glfwMakeContextCurrent((GLFWwindow*)wind.window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
return NULL;
}
glViewport(0, 0, screen_width, screen_height);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glEnable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
return &wind;
}
void LIB_GetWindowFrameSize(LIB_Window * window, int *width, int *height)
{
int screenwidth, screenheight;
glfwGetFramebufferSize(((GLFWwindow*)window->window), &screenwidth, &screenheight);
*width = screenwidth;
*height = screenheight;
}
void LIB_GetWindowCursorPosition(LIB_Window * window, float *x, float *y)
{
double cx, cy;
glfwGetCursorPos(((GLFWwindow*)window->window), &cx, &cy);
*x = (float)cx;
*y = (float)cy;
}
void LIB_GetDisplaySize(int *width, int *height)
{
const struct GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
*width = mode->width;
*height = mode->height;
}
void LIB_GetWindowPosition(LIB_Window * window, int *x, int *y)
{
*x = (window)->x;
*y = (window)->y;
}
void LIB_GetWindowSize(LIB_Window * window, int *width, int *height)
{
*width = (window)->width;
*height = (window)->height;
}
LIB_String LIB_GetWindowTitle(LIB_Window * window)
{
return (window)->title;
}
LIB_Bool LIB_IsWindowFullScreen(LIB_Window * window)
{
return (window)->fullscreen;
}
LIB_Bool LIB_IsWindowOpened(LIB_Window * window)
{
return !glfwWindowShouldClose(((GLFWwindow*)window->window));
}
void LIB_SwapWindowBuffers(LIB_Window * window)
{
glfwSwapBuffers(((GLFWwindow*)window->window));
}
void LIB_SetWindowPosition(LIB_Window * window, const int x, const int y)
{
glfwSetWindowPos(((GLFWwindow*)window->window), x,y);
(window)->x = x;
(window)->y = y;
}
void LIB_SetWindowSize(LIB_Window * window, const int width, const int height)
{
glfwSetWindowSize(((GLFWwindow*)window->window), width, height);
(window)->width = width;
(window)->height = height;
}
void LIB_SetWindowTitle(LIB_Window * window, const LIB_String title)
{
glfwSetWindowTitle(((GLFWwindow*)window->window), title);
(window)->title = title;
}
void LIB_SetFullScreenState(LIB_Window * window, const LIB_Bool fullscreen)
{
const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
if (fullscreen == LIB_FALSE)
{
glfwSetWindowMonitor(((GLFWwindow*)window->window), NULL, (window)->x, (window)->y, (window)->width, (window)->height, 60);
}
else if (fullscreen == LIB_TRUE)
{
glfwSetWindowMonitor(((GLFWwindow*)window->window), glfwGetPrimaryMonitor(), 0, 0, mode->width, mode->height, 60);
}
(window)->fullscreen = fullscreen;
}
void LIB_DestroyWindow(LIB_Window * window)
{
(window)->window = NULL;
(window)->title = NULL;
(window)->x = 0;
(window)->y = 0;
(window)->width = 0;
(window)->height = 0;
free(window);
}
void LIB_Terminate()
{
printf("BLITZ terminated by the user!!\n");
glfwTerminate();
}

The function LIB_CreateWindow returns a pointer to the loacal variable LIB_Window wind;. Once the function terminates, the variable goes out of scope and pointer points to "nowhere". This is an undefined behavior. Note, a local variable in a function is allocated on the stack, which is immediately freed, when the function is terminated.
You can fix this quickly, by declare the variable static:
static LIB_Window wind;
But, if you do so, then of course the library can only manage one window.
Either you create a dynamically allocated variable,
void LIB_CreateWindow( ..... )
{
.....
LIB_Window *newWnd = malloc( sizeof(LIB_Window) );
*newWnd = wind;
return newWnd;
}
or you declare the variable of type LIB_Window outside the function and provide it to the function by pointer:
void LIB_CreateWindow( LIB_Window *ptr_wnd, ..... );
int main( void )
{
.....
LIB_Window wind;
LIB_CreateWindow( &wnd, ..... );
.....
}
Of course, the memory release of the LIB_Window data structure, in the function LIB_DestroyWindow, only works if the memory for the variable was dynamically allocated:
LIB_DestroyWindow()
{
.....
free(window); // <--- this only works if window was allocated by malloc
}

Related

How can I increase the length of the snake and make it follow the head?

Can someone help me to increase the length of the snake and make it follow the head ?
I tried to develop a simple snake game without videos or help and did almost great but cannot figure out how to increase the size of the snake and move it properly.
I'd be very thankful
#include <SDL2/SDL.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#define LOG(x) printf("%s\n", x)
#define LOG_ERROR(x) fprintf(stderr, "Error: %s\n", x)
#define LOG_SDL_ERROR(x) fprintf(stderr, "%s: %s\n", x, SDL_GetError())
#define global_variable static
#define internal_function static
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define HEAD_SIZE 30
#define APPLE_SIZE 25
#define MAX_LENGHT 10
typedef const char* string;
typedef float realNum;
typedef struct Snake
{
SDL_Rect body[MAX_LENGHT];
int xSpeed;
int ySpeed;
int site;
realNum xPos;
realNum yPos;
} Snake;
typedef struct Apple
{
int xPos;
int yPos;
int size;
} Apple;
void checkColissions(Apple *apple, Snake *snake );
bool initGame(void);
void update(realNum);
void handleEvent(SDL_Event);
void renderGame(void);
void gameOver(void);
void shutdownGame(void);
Snake makeSnake(void);
void renderSnake(Snake *snake);
void updateSnake(Snake *, realNum);
Apple makeApple();
void renderApple(Apple *);
global_variable bool Running;
global_variable SDL_Window *g_pWindow;
global_variable SDL_Renderer *g_pRenderer;
Snake *g_pSnake = NULL;
Apple *g_pApple = NULL;
int
main(int argc, char const *argv[])
{
srand((unsigned int)time(NULL));
atexit(shutdownGame);
if (!initGame())
{
LOG_ERROR("Failed Initialization");
exit(1);
}
else
{
Running = true;
int fps = 330;
int desiredDelta = 1000/fps;
SDL_Event event;
while (Running)
{
renderGame();
update(desiredDelta);
handleEvent(event);
SDL_Delay(rand() % 30);
}
}
return (EXIT_SUCCESS);
}
bool
initGame()
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
LOG_SDL_ERROR("Failed initialization: ");
return (false);
}
else
{
g_pWindow =
SDL_CreateWindow("Snake", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
g_pRenderer =
SDL_CreateRenderer(g_pWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
g_pSnake = (Snake*)malloc(sizeof(Snake));
g_pApple = (Apple*)malloc(sizeof(Apple));
*g_pSnake = makeSnake();
*g_pApple = makeApple();
if ((g_pApple || g_pSnake || g_pRenderer || g_pWindow) == NULL)
{
return (false);
}
g_pWindow == NULL ? LOG_ERROR("Window failed") : LOG("Succes Window");
g_pRenderer == NULL ? LOG_ERROR("Renderer failed") : LOG("Succes Renderer");
g_pApple == NULL ? LOG_ERROR("Apple failed") : LOG("Succes Apple");
g_pSnake == NULL ? LOG_ERROR("Snake failed") : LOG("Succes Snake");
LOG("Game initialized");
}
return true;
}
void
renderGame()
{
SDL_SetRenderDrawColor(g_pRenderer, 0, 80, 0, 255);
SDL_RenderClear(g_pRenderer);
renderSnake(g_pSnake);
renderApple(g_pApple);
SDL_RenderPresent(g_pRenderer);
}
void update(realNum elapsed)
{
updateSnake(g_pSnake, elapsed);
checkColissions(g_pApple, g_pSnake);
}
void
handleEvent(SDL_Event event)
{
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
{
Running = false;
} break;
default:
break;
}
}
void
shutdownGame()
{
if (g_pWindow)
{
SDL_DestroyWindow(g_pWindow);
}
if (g_pRenderer)
{
SDL_DestroyRenderer(g_pRenderer);
}
if (g_pApple)
{
free(g_pApple);
}
if (g_pSnake)
{
free(g_pSnake);
}
SDL_Quit();
LOG("Game shutdowned");
}
Snake makeSnake(void)
{
const int speed = 0;
Snake snake = {
.xSpeed = speed,
.ySpeed = speed,
.xPos = SCREEN_WIDTH / 2,
.yPos = SCREEN_HEIGHT / 2,
.site = HEAD_SIZE
};
SDL_Rect SnakeRect = {
.h = snake.site,
.w = snake.site,
.x = snake.xPos,
.y = snake.yPos
};
snake.body[0] = SnakeRect;
return (snake);
}
void renderSnake(Snake *snake)
{
for (int i = 0; i < MAX_LENGHT; i++)
{
SDL_SetRenderDrawColor(g_pRenderer, 0, 0, 100, 255);
SDL_RenderFillRect(g_pRenderer, &snake->body[i]);
}
}
void updateSnake(Snake *snake, realNum elapsed)
{
const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
for (int i = 0; i < MAX_LENGHT; i++)
{
/* code */
snake->body[i].y += snake->ySpeed * elapsed;
snake->body[i].x += snake->xSpeed * elapsed;
}
/* code */
/* code */
/* code */
if (keyboardState[SDL_SCANCODE_W])
{
snake->ySpeed = -1;
snake->xSpeed = 0;
}
if (keyboardState[SDL_SCANCODE_D])
{
snake->ySpeed = 0;
snake->xSpeed = 1;
}
if (keyboardState[SDL_SCANCODE_A])
{
snake->ySpeed = 0;
snake->xSpeed = -1;
}
if (keyboardState[SDL_SCANCODE_S])
{
snake->ySpeed = 1;
snake->xSpeed = 0;
}
if (snake->body->x < 0 - HEAD_SIZE)
{
snake->body->x = SCREEN_WIDTH + HEAD_SIZE;
}
if (snake->body->x > SCREEN_WIDTH + HEAD_SIZE)
{
snake->body->x = 0 - HEAD_SIZE;
}
if (snake->body->y < 0 - HEAD_SIZE)
{
snake->body->y = SCREEN_HEIGHT + HEAD_SIZE;
}
if (snake->body->y > SCREEN_HEIGHT + HEAD_SIZE)
{
snake->body->y = 0 - HEAD_SIZE;
}
}
void
checkColissions(Apple *apple, Snake *snake )
{
SDL_Rect appleRect = {
.h = APPLE_SIZE,
.w = APPLE_SIZE,
.x = apple->xPos,
.y = apple->yPos
};
if (SDL_HasIntersection(&appleRect, snake->body))
{
*g_pApple = makeApple();
};
}
Can someone help me to increase the length of the snake and make it follow the head ?
Snake is defined by an array of coordinates, not just one (x,y). You need some kind of circular buffer, that can change capacity. Or you can just use an array, and then change every element of the array with every snake's move. And then you would realize that circular buffer is a really neat idea.
Once you have your buffer, be it an array or circular buffer, the question becomes how to move and enlarge the snake in it. It is simple. To move the snake you add one coordinate to the head, and remove one from the tail of the buffer. When the snake should become bigger you just don't remove the last element in the buffer. Add to the head, but don't remove the tail. This is how circular buffer would be handled. In case of a plain array moving means overwriting everything, and enlarging means adding to the beginning, and moving everything else by one place.

C realloc error: malloc(): invalid size (unsorted)

I am currently making a sdl2(/graphical) version of the game of life in C, so when the screen is resized I need to update the grid. When the screen is resized I don't want it to just change the size of the tiles, I want it to actually create more tiles. So I reallocate the cells list, which contains all of the cells states but for some odd reason that doesn't work.
bool updateCells(int w, int h) {
size_t x, y,
oldGridCol,
oldGridRow;
oldGridCol = gridCol;
oldGridRow = gridRow;
gridRow = w / gridSizeW;
gridCol = h / gridSizeH;
cells = (cellState_t *)realloc(cells, (gridRow * gridCol) * sizeof(cellState_t));
if(cells == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Memory allocation failed!");
return false;
}
for(y = 0; y < oldGridRow; y++) {
for(x = 0; x < oldGridCol; x++) {
writeCell(y, x, *(cells + (x + (y * oldGridCol))));
}
}
return false;
}
When this function is called the realloc function returns this:
malloc(): invalid size (unsorted)
Aborted
Thank you in advance!
I have made a minimal reproducible example of this program, which doesn't use SDL2, just plain C. Now for some reason this example works.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
typedef enum cellState {
dead,
live,
potentialDead,
potentialLive
} cellState_t;
size_t gridRow,
gridCol,
gridSizeW,
gridSizeH;
cellState_t *cells;
bool quitLoop;
bool initCells(void);
bool updateCells(int w, int h);
void writeCell(size_t row, size_t col, cellState_t state);
cellState_t readCell(size_t row, size_t col);
void die(const char *f, const size_t l, const char *fmt, ...);
int main(int argc, char *args[]) {
int w, h;
quitLoop = false;
gridSizeW = 25;
gridSizeH = 25;
// Let's assume that the window size is 640 by 480
gridRow = 640 / gridSizeW;
gridCol = 480 / gridSizeH;
if(!initCells())
die(__FILE__, __LINE__, "Failed to initialize cells!");
writeCell(1, 2, live);
writeCell(2, 3, live);
writeCell(3, 3, live);
writeCell(3, 2, live);
writeCell(3, 1, live);
while(!quitLoop) {
updateCells(640, 480);
printf("%d\n", readCell(1, 2));
}
return EXIT_SUCCESS;
}
bool initCells(void) {
cells = calloc((gridRow * gridCol), sizeof(cellState_t));
if(cells == NULL) {
return false;
}
return true;
}
bool updateCells(int w, int h) {
size_t x, y,
oldGridCol,
oldGridRow;
oldGridCol = gridCol;
oldGridRow = gridRow;
gridRow = w / gridSizeW;
gridCol = h / gridSizeH;
cells = (cellState_t *)realloc(cells, (gridRow * gridCol) * sizeof(cellState_t));
if(cells == NULL) {
return false;
}
for(y = 0; y < oldGridRow; y++) {
for(x = 0; x < oldGridCol; x++) {
writeCell(y, x, *(cells + (x + (y * oldGridCol))));
}
}
return false;
}
void writeCell(size_t row, size_t col, cellState_t state) {
*(cells + (col + (row * gridCol))) = state;
}
cellState_t readCell(size_t row, size_t col) {
return *(cells + (col + (row * gridCol)));
}
void die(const char *f, const size_t l, const char *fmt, ...) {
va_list vargs;
va_start(vargs, fmt);
fprintf(stderr, "error from file %s on line %ld: ", f, l);
//SDL_LogMessageV(SDL_LOG_CATEGORY_ERROR, SDL_LOG_PRIORITY_CRITICAL, fmt, vargs);
fputc('\n', stderr);
va_end(vargs);
exit(EXIT_FAILURE);
}
Maybe it's the window size variable that affects the outcome, or something like that.
But the full code doesn't work, here's the full code:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#define WINDOW_NAME "sdl-life"
#define WINDOWW 640
#define WINDOWH 480
typedef enum cellState {
dead,
live,
potentialDead,
potentialLive
} cellState_t;
SDL_Window *gWindow;
SDL_Renderer *gRenderer;
SDL_Texture *gLiveCellTexture,
*gGrid;
size_t gridRow,
gridCol,
gridSizeW,
gridSizeH;
cellState_t *cells;
bool quitLoop;
bool initSdl(void);
void closeSdl(void);
SDL_Texture *loadTexture(const char *path);
bool loadMedia(void);
bool initCells(void);
bool updateCells(int w, int h);
void writeCell(size_t row, size_t col, cellState_t state);
cellState_t readCell(size_t row, size_t col);
void displayCell(cellState_t status, SDL_Rect location);
void displayAllCells(void);
void die(const char *f, const size_t l, const char *fmt, ...);
int main(int argc, char *args[]) {
SDL_Event event;
int w, h;
quitLoop = false;
if(!initSdl())
die(__FILE__, __LINE__, "Failed to initialize SDL!");
if(!loadMedia())
die(__FILE__, __LINE__, "Failed to load media!");
SDL_GetWindowSize(gWindow, &w, &h);
gridSizeW = 25;
gridSizeH = 25;
gridRow = w / gridSizeW;
gridCol = h / gridSizeH;
if(!initCells())
die(__FILE__, __LINE__, "Failed to initialize cells!");
writeCell(1, 2, live);
writeCell(2, 3, live);
writeCell(3, 3, live);
writeCell(3, 2, live);
writeCell(3, 1, live);
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0x00);
while(!quitLoop) {
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT)
quitLoop = true;
}
SDL_RenderClear(gRenderer);
SDL_GetWindowSize(gWindow, &w, &h);
updateCells(w, h);
displayAllCells();
SDL_RenderPresent(gRenderer);
}
closeSdl();
return EXIT_SUCCESS;
}
bool initSdl(void) {
SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "The initialization process has begun");
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to initialize SDL: %s", SDL_GetError());
return false;
}
if(!IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to initialize SDL_image: %s", IMG_GetError());
return false;
}
if(TTF_Init() == -1) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to initialize SDL_ttf: %s", TTF_GetError());
return false;
}
gWindow = SDL_CreateWindow(WINDOW_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOWW, WINDOWH, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if(gWindow == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to create the window: %s", SDL_GetError());
return false;
}
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if(gRenderer == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to create the renderer: %s", SDL_GetError());
return false;
}
SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "The initialization has finished");
return true;
}
void closeSdl(void) {
SDL_LogVerbose(SDL_LOG_CATEGORY_APPLICATION, "SDL is shutting DOWN!");
free(cells);
SDL_DestroyTexture(gLiveCellTexture);
SDL_DestroyTexture(gGrid);
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(gWindow);
IMG_Quit();
TTF_Quit();
SDL_Quit();
}
SDL_Texture *loadTexture(const char *path) {
SDL_Texture *newTexture;
SDL_Surface *loadedSurface;
loadedSurface = IMG_Load(path);
if(loadedSurface == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to load surface: %s", IMG_GetError());
return NULL;
}
SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0x0, 0xff, 0xff));
newTexture = SDL_CreateTextureFromSurface(gRenderer, loadedSurface);
if(newTexture == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to convert surface to texture: %s", SDL_GetError());
return NULL;
}
SDL_FreeSurface(loadedSurface);
return(newTexture);
}
bool loadMedia(void) {
gLiveCellTexture = loadTexture("livecell.png");
if(gLiveCellTexture == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to load surface: %s", IMG_GetError());
return false;
}
gGrid = loadTexture("grid.png");
if(gGrid == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Failed to load surface: %s", IMG_GetError());
return false;
}
return true;
}
bool initCells(void) {
cells = calloc((gridRow * gridCol), sizeof(cellState_t));
if(cells == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Memory allocation failed!");
return false;
}
return true;
}
bool updateCells(int w, int h) {
size_t x, y,
oldGridCol,
oldGridRow;
oldGridCol = gridCol;
oldGridRow = gridRow;
gridRow = w / gridSizeW;
gridCol = h / gridSizeH;
cells = (cellState_t *)realloc(cells, (gridRow * gridCol) * sizeof(cellState_t));
if(cells == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Memory reallocation failed!");
return false;
}
for(y = 0; y < oldGridRow; y++) {
for(x = 0; x < oldGridCol; x++) {
writeCell(y, x, *(cells + (x + (y * oldGridCol))));
}
}
return false;
}
void writeCell(size_t row, size_t col, cellState_t state) {
*(cells + (col + (row * gridCol))) = state;
}
cellState_t readCell(size_t row, size_t col) {
return *(cells + (col + (row * gridCol)));
}
void displayCell(cellState_t status, SDL_Rect location) {
SDL_RenderCopy(gRenderer, gGrid, NULL, &location);
if(status == live) {
SDL_RenderCopy(gRenderer, gLiveCellTexture, NULL, &location);
}
}
void displayAllCells(void) {
size_t x, y;
SDL_Rect location;
location.w = gridSizeW;
location.h = gridSizeH;
location.x = 0;
location.y = 0;
for(y = 0; y < gridRow; y++) {
for(x = 0; x < gridCol; x++) {
displayCell(readCell(y, x), location);
location.x += location.w;
}
location.y += location.h;
location.x = 0;
}
}
void die(const char *f, const size_t l, const char *fmt, ...) {
va_list vargs;
va_start(vargs, fmt);
fprintf(stderr, "error from file %s on line %ld: ", f, l);
SDL_LogMessageV(SDL_LOG_CATEGORY_ERROR, SDL_LOG_PRIORITY_CRITICAL, fmt, vargs);
va_end(vargs);
closeSdl();
exit(EXIT_FAILURE);
}
My guess is that your problem occurs when you try to realloc cells to
gridRow * gridCol
since w / gridSizeW seems to be the amount of elements you want. Try:
cells = (cellState_t *)realloc(cells, (gridRow * gridCol) * sizeof(cellState_t));
Let's analize your code. The grid is a 2D-array named cells, which
you allocate dynamically basing on its dimensions which are kept in gridSizeW and gridSizeH.
Ideally to address a cell you use its coordinates which
would go from (1 to gridSizeW; 1 to gridSizeH) or instead, more commonly, from (0 to gridSizeW-1; 0 to gridSizeH-1).
Your routine to get the value of a cell is:
cellState_t readCell(size_t row, size_t col) {
return *(cells + (col + (row * gridCol)));
}
which implements the idea of taking the requested row number, multiply it for the width, and adding the column number. This is correct to turn a 2D address to a 1D one.
The problem is that your in-memory representation of the grid has nothing (or little) to do with the dimensions of the screen. If you have a grid 25 x 25 (you assign these as initial width and height), you must allocate 25*25 cells, no matter what SDL_GetWindowSize() returns to you.
Basically, you should always use gridSizeW and gridSizeH for coping with the cell pointer. You use instead gridRow and gridCol. Only when you update the screen, you perform a "scaling" of a row+column coordinate of then grid to an X+Y coordinate of the screen. So your readcell routine, assuming a 0-based numbering, should be:
cellState_t readCell(size_t row, size_t col) {
return *(cells + (col + (row * gridSizeW)));
// gridSizeW -------^
}
The variables gridRow and gridCol, which are the ratio of w/gridwidth and h/gridheight as you correctly wrote:
SDL_GetWindowSize(gWindow, &w, &h); // w+h: screen dimensions
gridSizeW = 25; // grid dimensions
gridSizeH = 25;
gridRow = w / gridSizeW; // screenwidth=250? then a cell is 10 pixels wide
gridCol = h / gridSizeH;
are to be used only when interfacing to SDL.

Animating GTK+ Windows

I am trying to create a smoothly animated window in GTK+
Here is the code I came up with:
#include <gtk/gtk.h>
typedef struct {
GtkWindow *window;
int timePassed;
int fromX;
int fromY;
int toX;
int toY;
int time;
int step;
void (*callback)(void*);
void *data;
} AnimationStructure;
double coolBezier(double t) {
double register one_minus_t_powered;
double register one_minus_t_;
one_minus_t_ = 1 - t;
one_minus_t_powered = one_minus_t_ * one_minus_t_;
return one_minus_t_powered * 0.0 + one_minus_t_ * 2.0 * t * -1.00 + t * t * 1.0;
}
gboolean animate_window_timeout(AnimationStructure *ani) {
double time = coolBezier((double) ani->timePassed / ani->time);
if (time >= 1.0) {
gtk_window_move(ani->window, ani->fromX + ani->toX, ani->fromY + ani->toY);
ani->callback(ani->data);
g_free(ani);
return FALSE;
}
printf("FromX: %d; FromY: %d\n", ani->fromX, ani->fromY);
gtk_window_move(ani->window, ani->fromX + (ani->toX * time), ani->fromY + (ani->toY * time));
ani->timePassed += ani->step;
return TRUE;
}
void animate_window(GtkWindow *window, int x, int y, int time, int step_time, void (*callback)(void*), void* data) {
AnimationStructure *ani = g_new(AnimationStructure, 1);
ani->window = window;
ani->toX = x;
ani->toY = y;
ani->timePassed = 0;
ani->time = time;
ani->step = step_time;
ani->callback = callback;
ani->data = data;
gtk_window_get_position(window, &(ani->fromX), &(ani->fromY));
g_timeout_add(step_time, (GSourceFunc) animate_window_timeout, ani);
}
int main (int argc, char *argv[]) {
GtkWindow *window;
gtk_init(&argc, &argv);
window = (GtkWindow*) gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(window, GTK_WIN_POS_CENTER);
gtk_window_set_default_size(window, 300, 300);
g_signal_connect_swapped(window, "destroy", gtk_main_quit, NULL);
animate_window(window, 300, 0, 1000, 15, NULL, NULL);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
return 0;
}
This works and when I applied it to the notification window the effect was like on this gif:
But the window is not smooth as I would like it to be, you can notice that at the end the window almost jumps 50px from left to right.

Pebble stopwatch change in font size bug

I have been trying to get an app working on my pebble for a while now and I finally got it to work. It's a sports counter that keeps track of the score for both teams and also has a built in stop watch in the middle. Everything works as it should but if the stopwatch runs for 42 seconds then the font for the counters become very small. I have no idea whats going on.
When I was looking around someone said it may be a memory leak, but this was not similar to my problem.
#include <pebble.h>
#define COUNTER_FONT_49 RESOURCE_ID_MACHINE_GUN_49
#define STOPWATCH_FONT_24 RESOURCE_ID_SPORTS_WORLD_24
#define HOME_AWAY_FONT_18 FONT_KEY_GOTHIC_18_BOLD
//---Counter Constants---
#define COUNTER_START 0
#define COUNTER_MAX 9999
#define COUNTER_MIN -9999
#define MAX_DIGITS 4
//---Interface Variables---
Window* window;
static Layer* layer;
static GFont counterFont;
static GFont stopwatchFont;
static TextLayer* teamAScore_layer;
static TextLayer* teamBScore_layer;
static TextLayer* big_time_layer;
static TextLayer* seconds_time_layer;
static TextLayer* home_away_layer;
//---Counter Variables---
char teamA_counter_text[MAX_DIGITS + 2 /* sign & \0 */];
char teamB_counter_text[MAX_DIGITS + 2 /* sign & \0 */];
int teamACounter;
int teamBCounter;
int singleClickIncrement;
int longClickIncrement;
int doubleClickIncrement;
//The Time
static double elapsed_time = 0;
static bool started = false;
static AppTimer* update_timer = NULL;
static double start_time = 0;
static double pause_time = 0;
time_t time_seconds();
void stop_stopwatch();
void start_stopwatch();
void handle_timer(void* data);
void update_stopwatch();
double float_time_ms() {
time_t seconds;
uint16_t milliseconds;
time_ms(&seconds, &milliseconds);
return (double)seconds + ((double)milliseconds / 1000.0);
}
void stop_stopwatch() {
started = false;
pause_time = float_time_ms();
if(update_timer != NULL) {
app_timer_cancel(update_timer);
update_timer = NULL;
}
}
void start_stopwatch() {
started = true;
if(start_time == 0) {
start_time = float_time_ms();
} else if(pause_time != 0) {
double interval = float_time_ms() - pause_time;
start_time += interval;
}
update_timer = app_timer_register(100, handle_timer, NULL);
}
void update_stopwatch() {
static char big_time[] = "00:00";
static char deciseconds_time[] = ".0";
static char seconds_time[] = ":00";
// Now convert to hours/minutes/seconds.
int tenths = (int)(elapsed_time * 10) % 10;
int seconds = (int)elapsed_time % 60;
int minutes = (int)elapsed_time / 60 % 60;
int hours = (int)elapsed_time / 3600;
// We can't fit three digit hours, so stop timing here.
if(hours > 99) {
stop_stopwatch();
return;
}
if(hours < 1) {
snprintf(big_time, 6, "%02d:%02d", minutes, seconds);
snprintf(deciseconds_time, 3, ".%d", tenths);
} else {
snprintf(big_time, 6, "%02d:%02d", hours, minutes);
snprintf(seconds_time, 4, ":%02d", seconds);
}
// Now draw the strings.
text_layer_set_text(big_time_layer, big_time);
text_layer_set_text(seconds_time_layer, hours < 1 ? deciseconds_time : seconds_time);
}
void select_click_long_handler(ClickRecognizerRef recognizer, Window *window) { //pressed SELECT LONG
bool is_running = started;
stop_stopwatch();
start_time = 0;
elapsed_time = 0;
if(is_running) start_stopwatch();
update_stopwatch();
}
static void select_click_handler(ClickRecognizerRef recognizer, void *context) { //pressed SELECT
if(started) {
stop_stopwatch();
} else {
start_stopwatch();
}
}
void handle_timer(void* data) {
if(started) {
double now = float_time_ms();
elapsed_time = now - start_time;
update_timer = app_timer_register(100, handle_timer, NULL);
}
update_stopwatch();
}
static int increment_value(int team_score, const int increment){
if(team_score + increment <= COUNTER_MAX && team_score + increment >= COUNTER_MIN)
team_score = team_score + increment;
return team_score;
}
static void up_multi_click_handler(ClickRecognizerRef recognizer, void *context) { //pressed UP MULTI
teamACounter = increment_value(teamACounter, doubleClickIncrement);
layer_mark_dirty(layer);
}
static void up_click_long_handler(ClickRecognizerRef recognizer, void *context) { //pressed UP LONG
teamACounter = increment_value(teamACounter, longClickIncrement);
layer_mark_dirty(layer);
}
static void up_click_handler(ClickRecognizerRef recognizer, void *context) { //pressed UP
teamACounter = increment_value(teamACounter, singleClickIncrement);
layer_mark_dirty(layer);
}
static void down_multi_click_handler(ClickRecognizerRef recognizer, void *context) { //pressed DOWN MULTI
teamBCounter = increment_value(teamBCounter, doubleClickIncrement);
layer_mark_dirty(layer);
}
static void down_click_long_handler(ClickRecognizerRef recognizer, void *context) { //pressed DOWN LONG
teamBCounter = increment_value(teamBCounter, longClickIncrement);
layer_mark_dirty(layer);
}
static void down_click_handler(ClickRecognizerRef recognizer, void *context) { //pressed DOWN
teamBCounter = increment_value(teamBCounter, singleClickIncrement);
layer_mark_dirty(layer);
}
static void click_config_provider(void *context) {
window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler);
window_long_click_subscribe(BUTTON_ID_SELECT, 700, (ClickHandler) select_click_long_handler, NULL);
window_single_click_subscribe(BUTTON_ID_UP, up_click_handler);
window_long_click_subscribe(BUTTON_ID_UP, 700, (ClickHandler)up_click_long_handler, NULL);
window_multi_click_subscribe(BUTTON_ID_UP, 2, 10, 0, true, up_multi_click_handler);
window_single_click_subscribe(BUTTON_ID_DOWN, down_click_handler);
window_long_click_subscribe(BUTTON_ID_DOWN, 700, (ClickHandler)down_click_long_handler, NULL);
window_multi_click_subscribe(BUTTON_ID_DOWN, 2, 10, 0, true, down_multi_click_handler);
}
static void update_layer(Layer *layer, GContext *ctx){
GRect bounds = layer_get_frame(layer);
counterFont = fonts_load_custom_font(resource_get_handle(COUNTER_FONT_49));
graphics_context_set_text_color(ctx, GColorBlack);
snprintf(teamA_counter_text, (MAX_DIGITS + 2)*sizeof(char), "%d", teamACounter);
graphics_draw_text(ctx,
teamA_counter_text,
counterFont,
GRect(0, 0, bounds.size.w - 10, 60),
GTextOverflowModeWordWrap,
GTextAlignmentCenter,
NULL);
snprintf(teamB_counter_text, (MAX_DIGITS + 2)*sizeof(char), "%d", teamBCounter);
graphics_draw_text(ctx,
teamB_counter_text,
counterFont,
GRect(0, 95, bounds.size.w - 10, 60),
GTextOverflowModeWordWrap,
GTextAlignmentCenter,
NULL);
}
static void window_load(Window *window) {
// Get the root layer
Layer *window_layer = window_get_root_layer(window);
// Get the bounds of the window for sizing the text layer
GRect bounds = layer_get_bounds(window_layer);
layer = layer_create(bounds);
layer_set_update_proc(layer, update_layer);
layer_add_child(window_layer, layer);
}
static void window_unload(Window *window) {
// Destroy TextLayer
text_layer_destroy(teamAScore_layer);
text_layer_destroy(teamBScore_layer);
text_layer_destroy(big_time_layer);
text_layer_destroy(seconds_time_layer);
}
void handle_init(void) {
window = window_create();
window_set_click_config_provider(window, click_config_provider);
window_set_window_handlers(window, (WindowHandlers) {
.load = window_load,
.unload = window_unload,
});
//Set the counters start
teamACounter = COUNTER_START;
teamBCounter = COUNTER_START;
//---------------------------------------------TEMPERARY INCREMENT
singleClickIncrement = 1;
doubleClickIncrement = 2;
longClickIncrement = 3;
Layer *root_layer = window_get_root_layer(window);
stopwatchFont = fonts_load_custom_font(resource_get_handle(STOPWATCH_FONT_24));
//-----Display Stop Watch-----
big_time_layer = text_layer_create(GRect(0, 65, 86, 35));
text_layer_set_text_alignment(big_time_layer, GTextAlignmentRight);
text_layer_set_background_color(big_time_layer, GColorClear);
text_layer_set_text(big_time_layer, "00:00");
text_layer_set_font(big_time_layer, stopwatchFont);
layer_add_child(root_layer, (Layer*)big_time_layer);
seconds_time_layer = text_layer_create(GRect(86, 65, 49, 35));
text_layer_set_text(seconds_time_layer, ".0");
text_layer_set_background_color(seconds_time_layer, GColorClear);
text_layer_set_font(seconds_time_layer, stopwatchFont);
layer_add_child(root_layer, (Layer*)seconds_time_layer);
//-----Display Home and Away-----
home_away_layer = text_layer_create(GRect(124, 0, 20, 152));
text_layer_set_text(home_away_layer, "\n H\n\n\n\n\n A");
text_layer_set_background_color(home_away_layer, GColorBlack);
text_layer_set_text_color(home_away_layer, GColorWhite);
text_layer_set_font(home_away_layer, fonts_get_system_font(HOME_AWAY_FONT_18));
layer_add_child(root_layer, (Layer*)home_away_layer);
const bool animated = true;
window_stack_push(window, animated);
}
void handle_deinit(void) {
window_destroy(window);
}
int main(void) {
handle_init();
app_event_loop();
handle_deinit();
}
You're loading the custom font into memory each time the update_layer function is called. Eventually the app runs out of memory and can't load the font any more, which is why it uses the fallback (really small) font.
You should just load the custom font once, in your init function.

OpenGL black screen/nothing drawn?

Why does this piece of code produce a black screen (nothing is drawn...)?
I'm creating a Pong clone but I can't proceed without getting this to work.
#include <GL/glut.h>
struct Rectangle {
int x;
int y;
int width;
int height;
};
struct Ball {
int x;
int y;
int radius;
};
typedef struct Rectangle Rectangle;
typedef struct Ball Ball;
Rectangle rOne, rTwo;
Ball ball;
void display(void);
void reshape(int w, int h);
void drawRectangle(Rectangle *r);
int main(int argc, char* argv[]) {
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(800,600);
glutCreateWindow("Pong");
gluOrtho2D(0,0,800.0,600.0);
rOne.x = 100;
rOne.y = 100;
rOne.width = 100;
rOne.height = 50;
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
drawRectangle(&rOne);
glFlush();
glutSwapBuffers();
}
void reshape(int w, int h) {
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,0,(GLfloat)w,(GLfloat)h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void drawRectangle(Rectangle *r) {
glBegin(GL_QUADS);
glVertex2i(r->x,r->y);
glVertex2i(r->x+(r->width-1),r->y);
glVertex2i(r->x+(r->width-1),r->y+(r->height-1));
glVertex2i(r->x,r->y+(r->height-1));
glEnd();
}
You're requesting an ortho projection with zero width:
gluOrtho2D(0,0,(GLfloat)w,(GLfloat)h);
This is probably what you meant:
gluOrtho2D(0,(GLfloat)w,0,(GLfloat)h);
Example:
#include <GL/glut.h>
typedef struct {
int x;
int y;
int width;
int height;
} Rect;
typedef struct {
int x;
int y;
int radius;
} Ball;
Rect rOne, rTwo;
Ball ball;
void display(void);
void reshape(int w, int h);
void drawRectangle(Rect *r);
int main(int argc, char* argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(800,600);
glutCreateWindow("Pong");
rOne.x = 100;
rOne.y = 100;
rOne.width = 100;
rOne.height = 50;
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
drawRectangle(&rOne);
glFlush();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,(GLfloat)w,0,(GLfloat)h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void drawRectangle(Rect *r)
{
glBegin(GL_QUADS);
glVertex2i(r->x,r->y);
glVertex2i(r->x+(r->width-1),r->y);
glVertex2i(r->x+(r->width-1),r->y+(r->height-1));
glVertex2i(r->x,r->y+(r->height-1));
glEnd();
}
Your problem lies here:
gluOrtho2D(0,0,800.0,600.0);
gluOrtho2D is not like glViewport. The parameter of gluOrtho2D are :
gluOrtho2D(left, right, bottom, top);
So you must call it like
gluOrtho(0, w, 0, h);

Resources