home download get support documentation weaver games

Weaver Reference Guide

This page is hosting the Weaver Reference Guide. It shall list all the relevant macros, global variables, data structures and functions present in Weaver API.

If you wish to see the code of some of these elements, please click in the title with the element's name.

All the source code present here is part of Weaver API, copyrighted by Thiago "Harry" Leucz Astrizi and licensed under GNU General Public Licence v3.

Index

  1. Data Structures
  2. Functions
  3. Global Variables
  4. Macros

Data Structures

camera

typedef struct vector4 camera;

A camera is a struct vector4 that stores information about what vector objects should be drawned in the screen and where to draw them. The variables "x" and "y" stores the camera coordinates. The "w" stores the camera's width and "z" is the camera's height.

Normally a camera draws averything occuping the whole screen. This behaviour can be changed storing the coordinates to where to draw in the pointers "previous", "next", "top" and "down". This is done when you call the function limit_camera.

circle

typedef struct vector3 circle;

A circle is in fact a vector3. The coordinates of the circle's center are stored in the variables "x" and "y". The circle's radius is stored in "z".

polygon

typedef struct vector2 polygon;

A polygon is in fact a vector2. But it can be attached to other vector2s.

A polygon with 1 vertex (henagon) would be a single vector2. Polygons with more vertices would have one vector2 for each vertex where 2 adjacent vertices will always be connected by the *next and *previous pointers. Their variables x and y will store the vertex's coordinates.

rectangle

typedef struct vector4 rectangle;

A rectangle represents a simple quadrilateral whose sides are always paralel with the screen sides. In fact, it is an alias for struct vector4 because any rectangle with these properties can be described using four variables. The variables "x" and "y" store the coordinates of the rectangle's upper left edge. The variable "w" is the width and "z" is the height.

surface

typedef struct surface{
  Pixmap pix;
  int width;
  int height;
  Pixmap mask;
} surface;

A surface represents an image, that can drawn or manipuled by other functions. Some functions as new_image can be used to create a new surface from a PNG image. You can also use the new_surface function to create an empty surface with a predefined width and height.

The surface's variables width and height stores the image's width and height. The pixmap pix stores a number that represents the image in the X Server. And the pixmap mask stores a number that represents a bitmap (a pixmap with only 2 colors) that determines which areas in the image are transparent.

struct vector2

struct vector2{
  float x, y;
  struct vector2 *previous, *next;
};

A vector is a structure able to store an ordered sequence of data. A vector2 is a structure able to store 2 ordered values. Both of them are floats.

They can represent anything that needs 2 floats to be defined. The coordinates of a point, the strenght applied in a body, the displacement of an object relative to a previous position, and much more. It stores these values in the variables "x" and "y".

They also have 2 pointers that can store other vector2s address. So you can use vector2s as nodes in a doubly-linked list. The two generic pointers that every vector2 have are named "previous" and "next".

struct vector3

struct vector3{
  float x, y, z;
  struct vector3 *previous, *top, *next;
};

A vector3 can be used to represent anything formed by 3 variables. A point in a 3D enviroment, information about circles, strenght applied in a 3-dimentional body, and much more. These values are stored in the variables "x", "y" and "z".

They also have pointers to connect with other vector3s. This can form more advanced data structure this way, like trees and graphs. These pointers are named "previous", "next" and "top".

struct vector4

struct vector4{
  float w, x, y, z;
  struct vector4 *previous, *next, *top, *down;
};

A vector4 can be used to represent anything formed by 4 variables. A point in the space-time, information about ellipses, rectangles and much more. The information is stored in the variables "w", "x", "y" and "z".

They also have pointers to connect with other vector4s. They can form this way more advanced data structure. These pointers are called "previous", "next", "top" and "down".

Functions

void
apply_texture(surface *texture, surface *destiny)

void apply_texture(struct surface *src, struct surface *dest){
  int x, y;
  if(src -> width < 1 || src -> height < 1)
    return;
  for(x = 0; x < dest -> width; x += src -> width)
    for(y = 0; y < dest -> height; y += src -> height){
      XCopyArea(_dpy, src -> pix, dest -> pix, _gc, 0, 0, src -> width,
                src -> height, x, y);
    }
  XFlush(_dpy);
}

This function fills the second surface with a texture provided by the first surface. Pixels marked as transparent in the destiny surface are kept as transparent.

This function returns nothing.

void
awake_the_weaver(void)

void awake_the_weaver(void){
  _initialize_screen();
  _initialize_keyboard();
  _initialize_mouse();
  srand(time(NULL));
  gettimeofday(&current_time, NULL);
  fps = 50;
  _music = 0;
  _sound = 0;
}

This is the first function that shall be called in a Weaver Game. It initializes all the variables and data required to use the other functions.

If you start a Weaver program with awake_the_weaver, you should call may_the_weaver_sleep to free any memory reserved by awake_the_weaver.

Notice that if you use the Weaver API with the Weaver Framework, these functions are positioned in your code automaticly.

This function returns nothing.

void
blit_masked_pixmap(Pixmap pix, Pixmap mask, surface *dest, int x_src, int y_src, int width, int height, int x_mask, int y_mask, int x_dest, int y_dest)

void blit_masked_pixmap(Pixmap pix, Pixmap mask, struct surface *dest,
                       int x_src, int y_src, int width, int height,
                       int x_mask, int y_mask, int x_dest, int y_dest){
  XSetClipMask(_dpy, _gc, mask);
  XSetClipOrigin(_dpy, _gc, x_dest - x_mask, y_dest - y_mask);
  XCopyArea(_dpy, pix, dest -> pix, _gc, x_src, y_src, width, height, x_dest,
            y_dest);
  XSetClipMask(_dpy, _gc, None);
  XFlush(_dpy);
}

A surface is formed by a pixmap (a matrix of colors) and a mask (a matrix of 1s and 0s, defining what bits in the image should be drawn). When you use a command to draw a surface in the screen, the image is formed combining the surface's pixmap and mask. But using this function, you can draw an image in some surface (including the window) combining a surface's pixmap with the mask found in some other surface.

The first and second arguments are the pixmap and mask that should be used. The third is the destiny. Then we define what rectangular area from the pixmap should we use passins as arguments the (x,y) coordinate of the left upper vertex and the rectangle's width and height. The next two values are the coordinates of a rectangle with the same size in the mask that we should use to compose the image. And finally, the (x,y) coordinate in where we should draw the result in the destiny.

For example, if we have the surfaces "smile" and "fog", and we wish to draw in the upper left part of the screen the smile pixmap with the fog mask. Assuming that the two surfaces have the same dimensions, and we wish to draw the entire image, we should use:

  blit_masked_pixmap(smile -> pix, fog -> mask, window, 0, 0,
                     smile -> width, smile -> height, 0, 0, 0, 0);

This function returns nothing.

void
blit_surface(surface *src, surface *dest, int x_src, int y_src, int width, int height, int x_dest, int y_dest)

void blit_surface(struct surface *src, struct surface *dest, int x_src,
                  int y_src, int width, int height, int x_dest, int y_dest){
  // If the source surface has some transparent pixels, we need to take into
  // account this:
  if(src -> mask != None){
    XSetClipMask(_dpy, _gc, src -> mask);
    XSetClipOrigin(_dpy, _gc, x_dest - x_src, y_dest - y_src);
  }
  XCopyArea(_dpy, src -> pix, dest -> pix, _gc, x_src, y_src, width, height,
            x_dest, y_dest);
  XSetClipMask(_dpy, _gc, None);
  XFlush(_dpy);
}

This function copies a rectangle whose upper left vertex is in coordinate (x_src, y_src) and whose width and height is passed as argument from the surface "src" and copies it in the surface "dest".

Pixels with transparent values aren't copied.

This function returns nothing.

void
center_camera(camera *cam, float x, float y)

void center_camera(struct vector4 *camera, float x, float y){
  camera -> x = x - (camera -> w / 2);
  camera -> y = y - (camera -> z / 2);
}

This centers the camera in coordinate (x, y). It doesn't change the camera's size, only it's position.

This function returns nothing.

void
clean_keyboard(void)

#define clean_keyboard() _initialize_keyboard()

This function cleans the keyboard buffer. You can use it when you wants to ignore keys pressed during a frame or doesn't want to have keys previously pressed to interfere with future events.

This function returns nothing.

int
collision_circle_circle(circle *circ1, circle *circ2)

int collision_circle_circle(struct vector3 *circle1, struct vector3 *circle2){
  float dx = circle2 -> x - circle1 -> x;
  float dy = circle2 -> y - circle1 -> y;
  float distance = dx * dx + dy * dy;
  float minimum = circle1 -> z + circle2 -> z;

  minimum *= minimum;
  if(distance < minimum)
    return 1;
  else
    return 0;
}

This function receives as argument two circles. If they are in collision, the function returns 1. Else, it returns 0.

int
collision_circle_polygon(circle *circ, polygon *poly)

int collision_circle_polygon(struct vector3 *circle, struct vector2 *polygon){
  struct vector2 *current, *next, *first;
  float a, b, dist;

  current = first = polygon;
  next = current -> next;

  if(next == current){ // We have a degenerate polygon with only one vertex
    dist = (current -> x - circle -> x);
    dist *= dist; // dx * dx
    dist += (current -> y - circle -> y) * (current -> y - circle -> y);
    if(sqrt(dist) < circle -> z)
      return 1; // A collision happenned
    else
      return 0; // No collision happening
  }

  // This loops a number of times equal the number of polygon's sides
  // when the polygon isn's degenerated.
  do{
    // If it's not a vertical segment:
    if(current -> x != next -> x){
      a = (next -> y - current -> y) / (next -> x - current -> x);
      b = current -> y - a * current -> x;
      // Rect equation: ax + b = y
      dist = circle -> x * a - circle -> y + b;
      if(dist < 0.0)
        dist *= -1;
      dist /= sqrt(a * a + 1);
      // distance between rect and  point computed
      if(dist < circle -> z){
	// A collision happened or not
	if(!((circle -> x + circle -> z < current -> x && circle -> x + circle -> z < next-> x &&
              circle -> x - circle -> z < current -> x && circle -> x - circle -> z < next-> x) ||
             (circle -> x + circle -> z > current -> x && circle -> x + circle -> z > next-> x &&
              circle -> x - circle -> z > current -> x && circle -> x - circle -> z > next-> x))){
	  if(!((circle -> y + circle -> z < current -> y && circle -> y + circle -> z < next-> y &&
		circle -> y - circle -> z < current -> y && circle -> y - circle -> z < next-> y) ||
	       (circle -> y + circle -> z > current -> y && circle -> y + circle -> z > next-> y &&
		circle -> y - circle -> z > current -> y && circle -> y - circle -> z > next-> y))){
	    return 1;
	  }
        }
      }
    }
    else{ // We have a vertical segment
      if(!((circle -> x - circle -> z < current -> x && circle -> x + circle -> z < current -> x) ||
           (circle -> x - circle -> z > current -> x && circle -> x + circle -> z > current -> x))){
	// A collision happened... or not?
	if(!((circle -> y + circle -> z < current -> y && circle -> y + circle -> z < next-> y &&
              circle -> y - circle -> z < current -> y && circle -> y - circle -> z < next-> y) ||
             (circle -> y + circle -> z > current -> y && circle -> y + circle -> z > next-> y &&
	      circle -> y - circle -> z > current -> y && circle -> y - circle -> z > next-> y))){
          return 1; // COLLISION!
	}
      }
    }
    current = next;
    next = current -> next;
  }while(current != first);

  return 0;
}

This function receives as argument a circle and a polygon. If the 2 are colliding (exists at least 1 point of the polygon's perimeter inside the circle), it returns 1. Otherwise, it returns 0.

This function works obtaining the equation of the rect that crosses all the points of each polygon's edge. If this rect doesn't collide with the circle, there's no reason to do other operations and returns 0. Otherwise, we must check if the closest rect's point to the circle's center is in the polygon's edge. If so, returns 1. Else, returns 0. Vertical segments are treated differently to prevent division by 0.

int
collision_circle_rectangle(circle *circ, rectangle *rect)

#define collision_circle_rectangle(a, b) collision_rectangle_circle(b, a)

This function receives as argument respectively a circle and a rectangle. If they are in collision, the function returns 1. Else, it returns 0.

int
collision_polygon_circle(polygon *poly, rectangle *rect)

#define collision_polygon_circle(a, b) collision_circle_polygon(b, a)

This function receives as argument a polygon and a circle. If the 2 are colliding (exists at least 1 point of the polygon's perimeter inside the circle), it returns 1. Otherwise, it returns 0.

int
collision_polygon_polygon(polygon *p1, polygon *p2)

int collision_polygon_polygon(struct vector2 *poly1, struct vector2 *poly2){
  struct vector2 *first, *current, *next;
  struct vector2 *first2, *current2, *next2;

  current = first = poly1;
  next = current -> next;
  current2 = first2 = poly2;
  next2 = current2 -> next;

  if(current == next){ // This polygon is a henagon
    if(current2 == next2){ // We have 2 henagons!
      if(current -> x == current2 -> x &&
         current -> y == current2 -> y)
        return 1;
      else
        return 0;
    }
    else{ // The second polygon is not a henagon
      float a, b; // ax + b = y
      do{
        a = (next2 -> y - current2 -> y) / (next2 -> x - current2 -> x);
        b = current2 -> y - a * current2 -> x;
        if(a * current -> x + b == current -> y)
          return 1; // Detected a collision (unlikely to happen with henagons).
        current2 = next2;
        next2 = current2 -> next;
      }while(current2 != first2);
    }
  }
  else{ // The first polygon is not a henagon
    if(current2 == next2){ // But in this case, the second is
      float a, b;
      do{
        a = (next -> y - current -> y) / (next -> x - current -> x);
        b = current -> y - a * current -> x;
        if(a * current2 -> x + b == current2 -> y)
          return 1; // Collision detected.
        current = next;
        next = current -> next;
      }while(current != first);
    }
    else{ // The most common case. No henagons
      float a1, a2, b1, b2, x, y;
      a1 = a2 = b1 = b2 = y = 0.0;

      do{
        do{
          if(next -> x != current -> x){ // The first line is not vertical
            if(next2 -> x != current2 -> x){ // The second line is not vertical
              a1 = (next -> y - current -> y) / (next -> x - current -> x);
              b1 = current -> y - a1 * current -> x;
              a2 = (next2 -> y - current2 -> y) / (next2 -> x - current2 -> x);
              b2 = current2 -> y - a2 * current2 -> x;
              if(a1 != a2){ // Not paralells
                x = (b2 - b1) / (a1 - a2);
                if(!((x < current -> x && x < next -> x) ||
                     (x > current -> x && x > next -> x)))
                  return 1; // Collision !
              }
              else if(b1 == b2)
                return 1;
            }
            else{ // Only the second line is vertical
              y = a1 * current2 -> x + b1;
              if(!((y < current -> y && y < next -> y) ||
                   (y > current -> y && y > next -> y)))
                return 1; // Collision !
            }
          }
          else{ // The first line is vertical
            if(next2 -> x != current2 -> x){ // But the second is not
              y = a2 * current -> x + b2;
              if(!((y < current2 -> y && y < next2 -> y) ||
                   (y > current2 -> y && y > next2 -> y)))
                return 1; // Other collision case.
            }
            else{ // The 2 lines are vertical
              if(current -> y == current2 -> y)
                return 1;
            }
          }
        }while(current2 != first2);
        current = next;
        next = current -> next;
      }while(current != first);
    }
  }

  return 0;
}

This function receives as argument two polygons and return 1 if the polygon's perimeters are collidig and 0 otherwise. It checks for collisions in all edges.

int
collision_polygon_rectangle(polygon *poly, rectangle *rect)

#define collision_polygon_rectangle(a, b) collision_rectangle_polygon(b, a)

This function receives as argument a polygon and a rectangle. If exists at least one point in the polygon's perimeter that is inside the rectangle or in it's perimeter, then a collision is detected and the function returns 1. Otherwise, the function returns 0.

int
collision_rectangle_circle(rectangle *rect, circle *circ)

int collision_rectangle_circle(struct vector4 *rectangle, struct vector3 *circle){
  if(!((circle -> x + circle -> z < rectangle -> x && circle -> x - circle -> z < rectangle -> x &&
     circle -> x + circle -> z < rectangle -> x + rectangle -> w &&
      circle -> x - circle -> z < rectangle -> x + rectangle -> w) ||
     (circle -> x + circle -> z > rectangle -> x && circle -> x - circle -> z > rectangle -> x &&
     circle -> x + circle -> z > rectangle -> x + rectangle -> w &&
      circle -> x - circle -> z > rectangle -> x + rectangle -> w)))
    if(!((circle -> y + circle -> z < rectangle -> y && circle -> y - circle -> z < rectangle -> y &&
     circle -> y + circle -> z < rectangle -> y + rectangle -> z &&
	  circle -> y - circle -> z < rectangle -> y + rectangle -> z) ||
	 (circle -> y + circle -> z > rectangle -> y && circle -> y - circle -> z > rectangle -> y &&
     circle -> y + circle -> z > rectangle -> y + rectangle -> z &&
	  circle -> y - circle -> z > rectangle -> y + rectangle -> z)))
      return 1;

  // If no collision were detected, no collision happened
  return 0;
}

This function receives as argument a rectangle and a circle. If the two are colliding (their perimeter have at least one point in common, or one is inside the other), the function returns 1. Otherwise, it returns 0.

int
collision_rectangle_polygon(rectangle *rect, polygon *poly)

int collision_rectangle_polygon(struct vector4 *r, struct vector2 *p){
  struct vector2 *current, *next, *first;
  float x1, x2, y1, y2;

  current = first = p;
  next = current -> next;

  if(next == current){ // We have a degenerated polygon with a single vertex
    if(p -> x >= r -> x && p -> x <= r -> x + r -> w)
      if(p -> y >= r -> y && p -> y <= r -> y + r -> z)
	return 1;
    return 0;
  }

  do{ // Loops in all the polygon's vertices
    x1 = MIN(current -> x, next -> x);
    x2 = MAX(current -> x, next -> x);
    if(!(x1 > r -> x + r -> w || x2 < r -> x)){
      y1 = MIN(current -> y, next -> y);
      y2 = MAX(current -> y, next -> y);
      if(!(y1 > r -> y + r -> z || y2 < r -> y)){ // The edge is next. Perhaps
	                                                                          // it's colliding...
        if(x1 == x2 || y1 == y2){ // We have a vertical or horizontal edge
	  return 1; // It certainly collides in this case
	}
	else{ // We have a non-vertical edge
	  float a = (next -> y - current -> y) / (next -> x - current -> x);
	  float b = current -> y - a * current -> x;
	  // Now we have an ax+b=y rect equation
	  if((a * r -> x + b >= r -> y) && (a * r -> x + b <= r -> y + r -> z))
	    return 1; // Collided with the left side
	  if((a * (r -> x + r -> w) + b >= r -> y) &&
	     (a * (r -> x + r -> w) + b <= r -> y + r -> z))
	    return 1; // Collided with the right side
	  if(((r -> y - b)/a >= r -> x) && ((r -> y - b)/a <= r -> x + r -> w))
	    return 1; // Collided with the top side
	  if(((r -> y + r -> z - b)/a >= r -> x) &&
	     ((r -> y + r -> z - b)/a <= r -> x + r -> w))
	    return 1; // Collided with the down side
      }
    }
    current = next;
    next = current -> next;
  }while(current != first);

  return 0;
}

This function receives as argument a rectangle and a polygon. If exists at least one point in the polygon's perimeter that is inside the rectangle or in it's perimeter, then a collision is detected and the function returns 1. Otherwise, the function returns 0.

int
collision_rectangle_rectangle(rectangle *rec1, rectangle *rec2)

int collision_rectangle_rectangle(struct vector4 *r1, struct vector4 *r2){
  float dx = (r2 -> x - r1 -> x < 0) ? (r1 -> x - r2 -> x) : (r2 -> x - r1 -> x);
  if((r1 -> x < r2 -> x) ? (dx <= r1 -> w) : (dx <= r2 -> w)){
    float dy = (r2 -> y - r1 -> y < 0) ? (r1 -> y - r2 -> y) : (r2 -> y - r1 -> y);
    if((r1 -> y < r2 -> y) ? (dy <= r1 -> z) : (dy <= r2 -> z))
      return 1;
  }
  return 0;
}

This function detects collision between two rectangles passed as argument. If the rctangle's perimeter have at least one point in common or if there's one polygon inside the other, it returns 1. Otherwise, the function returns 0.

void
connect_vector2(struct vector2 *first, struct vector2 *second)

void connect_vector2(struct vector2 *a, struct vector2 *b){
  a -> next = b;
  b -> previous = a;
}

This function connects two vector2s. The second vector's address is stored in the first "next" pointer and the first vector's address is stored in the second's "previous" pointer.

This function doesn't return any value.

DEBUG_TIMER_START()
DEBUG_TIMER_STOP()

#define DEBUG_TIMER_START() { struct timeval _begin, _end; \
XFlush(_dpy); \
gettimeofday(&_begin, NULL);
#define DEBUG_TIMER_STOP() gettimeofday(&_end, NULL); \
printf("%ld\n", (1000000 * (_end.tv_sec - _begin.tv_sec) + \
_end.tv_usec - _begin.tv_usec)); \
}

These two macro functions must be used together, or an compilation error will happen. DEBUG_TIMER_START() basically starts a chronometer and DEBUG_TIMER_STOP() stops it and prints in the standard output the ammount of nanoseconds passed. These functions can be useful for measuring the time spent by functions or loops.

These two functions return nothing.

void
destroy_camera(void *camera)

#define destroy_camera(a) free(a)

This function can be used to free the space allocated by a camera. In fact, its an alias for "free", but for readability reasons, don't use it in objects that aren't cameras.

This function returns nothing.

void
destroy_circle(void *circle)

#define destroy_circle(a) free(a)

This function can be used to free the space allocated by a circle. In fact, its an alias for "free", but for readability reasons, don't use it in objects that aren't circles.

This function returns nothing.

void
destroy_polygon(struct vector2 *poly)

void destroy_polygon(struct vector2 *poly){
  struct vector2 *first_vector = poly;
  struct vector2 *current_vector, *temp;
  if(poly == NULL)
    return;
  current_vector = first_vector;
  do{
    temp = current_vector;
    current_vector = current_vector -> next;
    free(temp);
  }while(current_vector != first_vector);
}

This frees the memory alocated for some polygon. Please, pass to the function only well-formed polygons or a Segmentation Fault can happen. All polygons generated by new_polygon are well-formed.

void
destroy_rectangle(void *rectangle)

#define destroy_rectangle(a) free(a)

This frees the space in memory allocated for some rectangle. In fact, it's an alias for free function. But for readability reasons, avoid to use this function in anythig that isn't a rectangle.

This function returns nothing.

void
destroy_surface(surface *surf)

void destroy_surface(struct surface *my_surf){
  XFreePixmap(_dpy, my_surf -> pix);
  XFreePixmap(_dpy, my_surf -> mask);
  free(my_surf);
}

This frees the space in memory allocated for some surface.

This function returns nothing.

void
destroy_vector2(void *vector)

#define destroy_vector2(x) free(x)

This frees the space in memory allocated for some struct vector2. In fact, it's an alias for free function. But for readability reasons, avoid to use this function in anythig that isn't a struct vector2.

This function returns nothing.

void
destroy_vector3(void *vector)

#define destroy_vector3(x) free(x)

This frees the space in memory allocated for some struct vector3. In fact, it's an alias for free function. But for readability reasons, avoid to use this function in anythig that isn't a struct vector3.

void
destroy_vector4(void *vector)

#define destroy_vector4(x) free(x)

This frees the space in memory allocated for some struct vector4. In fact, it's an alias for free function. But for readability reasons, avoid to use this function in anythig that isn't a struct vector4.

void
draw_circle(unsigned x, unsigned y, unsigned radius, unsigned color)

void draw_circle(unsigned x, unsigned y, unsigned r, unsigned color){
  unsigned diameter = r + r;
  XSetForeground(_dpy, _gc, color);
  XDrawArc(_dpy, _w, _gc, x-r, y-r, diameter, diameter, 0, 23040);
  XFlush(_dpy);
}

This function draws a circle in the screen. The circle's center will be in the coordinate (x, y) and it's radius and color are the values passed as argument.

This function returns nothing.

void
draw_ellipse(unsigned x, unsigned y, unsigned width, unsigned height, unsigned color)

void draw_ellipse(unsigned x, unsigned y, unsigned width, unsigned height, unsigned color){
  XSetForeground(_dpy, _gc, color);
  XDrawArc(_dpy, _w, _gc, x - width / 2, y - height / 2, width, height, 0, 23040);
  XFlush(_dpy);
}

This function draws in the screen an ellipse whose center is in the coordinate (x, y), and whose maximum height, maximum width and color are passed as arguments.

This function returns nothing.

void
draw_line(unsigned x1, unsigned y1, unsigned x2, unsigned y2, unsigned color)

void draw_line(unsigned x1, unsigned y1, unsigned x2, unsigned y2, unsigned color){
  XSetForeground(_dpy, _gc, color);
  XDrawLine(_dpy, _w, _gc, x1, y1, x2, y2);
  XFlush(_dpy);
}

This function receives two coordinates (x1, y1) and (x2, y2) draws a lie in the screen that connects the two points. The color used is the one passed as argument.

This function returns nothing.

void
draw_point(unsigned x, unsigned y, unsigned color)

void draw_point(unsigned x, unsigned y, unsigned color){
  XSetForeground(_dpy, _gc, color);
  XDrawPoint(_dpy, _w, _gc, x, y);
  XFlush(_dpy);
}

This function draws a point in the screen at coordinate (x, y) using the color passed as argument.

This function returns nothing.

void
draw_rectangle(unsigned x, unsigned y, unsigned width, unsigned height, unsigned color)

void draw_rectangle(unsigned x, unsigned y, unsigned width, unsigned height, unsigned color){
  XSetForeground(_dpy, _gc, color);
  XDrawRectangle(_dpy, _w, _gc, x, y, width, height);
  XFlush(_dpy);
}

This function draws in the screen a rectangle whose upper left vertex is in coordinate (x, y) and whose width, height and color are passed as arguments.

This function returns nothing.

void
draw_rectangle_mask(surface *surf, int x, int y, int width, int height)

void draw_rectangle_mask(struct surface *my_surf, int x, int y, int width, int height){
  XSetForeground(_dpy, _mask_gc, 0l);
  XFillRectangle(_dpy, my_surf -> mask, _mask_gc, x, y, width, height);
  XFlush(_dpy);
}

This function marks as transparent a rectangular area in the surface. The rectangle's upper left vertex is in coordinate (x, y) (in the surface, not in the screen) and it's width and height is also passed as argument.

Any area marked as transparent is ignored when you draw a surface in the screen. So this function is used to erase parts of an image.

This function returns nothing.

void
draw_surface(surface *origin, surface *destiny, int x, int y)

#define draw_surface(a, b, x, y) blit_surface(a, b, 0, 0, a -> width, a -> height, x, y)

This function draws a surface in another surface at the coordinate (x, y).

This function returns nothing.

void
erase_fullpolygon(camera *cam, polygon *poly)

#define erase_fullpolygon(a, b) _film_fullpolygon(a, b, NOT_IMPORTANT, 1)

This function films a polygon in the screen, but using as texture the pixels stored in the background surface. This in fact, erase a polygon previously drawn with film_fullpolygon function.

This function returns nothing.

void
erase_fullrectangle(camera *cam, rectangle *rec)

#define erase_fullrectangle(a, b) _erase_rectangle(a, b, 1)

This function draws a rectangle in the screen using as texture the same pixels stored in the backgroud surface. It should have the effect of erasing a previously drawn rectangle (using film_rectangle function) from the screen.

This function returns nothing.

void
erase_polygon(camera *cam, polygon *poly)

#define erase_polygon(a, b) _film_polygon(a, b, NOT_IMPORTANT, 1)

This function draws a polygon perimeter in the screen using as texture the background surface. This erases a polygon drawn with the film_polygon function.

This function returns nothing.

void
erase_rectangle(camera *cam, rectangle *rect)

#define erase_rectangle(a, b) _erase_rectangle(a, b, 0)

This function draws a rectangle perimeter in the screen using as texture the same pixels stored in the backgroud surface. It should have the effect of erasing a previously drawn rectangle (using film_rectangle function) from the screen.

This function returns nothing.

void
erase_screen(void)

#define erase_screen() draw_surface(background, window, 0, 0)

This function fills the screen with the background content.

void
fill_circle(unsigned x, unsigned y, unsigned radius, unsigned color)

void fill_circle(unsigned x, unsigned y, unsigned r, unsigned color){
  unsigned diameter = r + r;
  XSetForeground(_dpy, _gc, color);
  XDrawArc(_dpy, _b, _gc, x - r, y - r, diameter, diameter, 0, 23040);
  XFillArc(_dpy, _w, _gc, x - r, y - r, diameter, diameter, 0, 23040);
  XFlush(_dpy);
}

This function draws and fills with the passed color a circle whose center is in the coordinate (x, y) and whose radius is the value passed as argument.

This function returns nothing.

void
fill_ellipse(unsigned x, unsigned y, unsigned width, unsigned height, unsigned color)

void fill_ellipse(unsigned x, unsigned y, unsigned width, unsigned height, unsigned color){
  XSetForeground(_dpy, _gc, color);
  XDrawArc(_dpy, _w, _gc, x - width / 2, y - height / 2, width, height, 0, 23040);
  XFillArc(_dpy, _w, _gc, x - width / 2, y - height / 2, width, height, 0, 23040);
  XFlush(_dpy);
}

This function draws and fills an ellipse whose center is in coordinate (x, y) and whose width, height and color are the values passed as argument.

This function returns nothing.

void
fill_rectangle(unsigned x, unsigned y, unsigned width, unsigned height, unsigned color)

void fill_rectangle(unsigned x, unsigned y, unsigned width, unsigned height, unsigned color){
  XSetForeground(_dpy, _gc, color);
  XFillRectangle(_dpy, _w, _gc, x - 1, y, width + 2, height + 1);
  XFlush(_dpy);
}

This function draws and fills a rectangle whose upper left vertex is in the coordinate (x, y) and whose width, height and color are the values passed as argument.

This function returns nothing.

void
fill_screen(unsigned color)

#define fill_screen(x) fill_rectangle(0, 0, window_width, window_height, x)

This function fills all the screen with the color passed as argument.

This function returns nothing.

void
fill_surface(surface *surf, unsigned color)

void fill_surface(struct surface *surf, unsigned color){
  XSetForeground(_dpy, _gc, color);
  XFillRectangle(_dpy, surf -> pix, _gc, 0, 0, surf -> width, surf -> height);
  XFlush(_dpy);
}

This function fills a surface with a solid color. Transparent areas doesn't lose the transparency.

This function returns nothing.

void
film_circle(camera *cam, circle *circ, unsigned color)

void film_circle(struct vector4 *camera, struct vector3 *circle, unsigned color){
  int x, y, height, width, limited_camera;
  limited_camera = 0;

  x = (int) (((circle -> x - camera -> x) / camera -> w) * window_width);
  y = (int) (((circle -> y - camera -> y) / camera -> z) * window_height);
  height = 2 * (int) ((circle -> z / camera -> z) * window_height);
  width = 2 * (int) ((circle -> z / camera -> w) * window_width);
  if(camera -> previous != NULL || camera -> next != NULL){
    limited_camera ++;
    x = (int) ((float) x * ((float) (long) camera -> next) / (float) window_width) + (long) (camera -> previous);
    width = (int) ((float) width * ((float) (long) camera -> next) / (float) window_width);
  }
  if(camera -> top != NULL || camera -> down != NULL){
    limited_camera ++;
    y = (int) ((float) y * ((float) (long) camera -> down) / (float) window_height) + (long) (camera -> top);
    height = (int) ((float) height * ((float) (long) camera -> down) / (float) window_height);
  }
  if(limited_camera){
    if(circle -> x < (long) camera -> x + (long) camera -> w + (long) (2 * circle -> z) &&
       circle -> x > (long) camera -> x - (long) (2 * circle -> z) &&
       circle -> y < (long) camera -> y + (long) camera -> z + (long) (2 * circle -> z) &&
       circle -> y > (long) camera -> y - (long) (2 * circle -> z)){
      // Creating a temporary and transparent surface
      struct surface *surf = new_surface((long) camera -> next, (long) camera -> down);
      XSetForeground(_dpy, _mask_gc, 0l);
      XFillRectangle(_dpy, surf -> mask, _mask_gc, 0, 0, surf -> width, surf -> height);

      // Drawing the circle in the surface
      XSetForeground(_dpy, _gc, color);
      XDrawArc(_dpy, surf -> pix, _gc, x - width / 2, y - height / 2, width, height, 0, 23040);

      // Drawing the circle in the transparency map
      XSetForeground(_dpy, _mask_gc, ~0l);
      XDrawArc(_dpy, surf -> mask, _mask_gc, x - width / 2, y - height / 2, width, height, 0, 23040);

      // Blitting the surface in the screen
      blit_surface(surf, window, 0, 0, surf -> width, surf -> height,
	    	   (long) camera -> previous, (long) camera -> top);

      destroy_surface(surf);
    }
  }
  else
    draw_ellipse(x, y, width, height, color);
}

This function draws a circle passed as argument using the referential stored by the camera passed as the first argument using the color passed as third argument.

This function returns nothing.

void
film_fullcircle(camera *cam, circle *circ, unsigned color)

void film_fullcircle(struct vector4 *camera, struct vector3 *circle, unsigned color){
  int x, y, height, width, limited_camera;
  limited_camera = 0;

  x = (int) (((circle -> x - camera -> x) / camera -> w) * window_width);
  y = (int) (((circle -> y - camera -> y) / camera -> z) * window_height);
  height = 2 * (int) ((circle -> z / camera -> z) * window_height);
  width = 2 * (int) ((circle -> z / camera -> w) * window_width);
  if(camera -> previous != NULL || camera -> next != NULL){
    limited_camera ++;
    x = (int) ((float) x * ((float) (long) camera -> next) / (float) window_width) + (long) (camera -> previous);
    width = (int) ((float) width * ((float) (long) camera -> next) / (float) window_width);
  }
  if(camera -> top != NULL || camera -> down != NULL){
    limited_camera ++;
    y = (int) ((float) y * ((float) (long) camera -> down) / (float) window_height) + (long) (camera -> top);
    height = (int) ((float) height * ((float) (long) camera -> down) / (float) window_height);
  }
  if(limited_camera){
    if(circle -> x < (long) camera -> x + (long) camera -> w + (long) (2 * circle -> z) &&
       circle -> x > (long) camera -> x - (long) (2 * circle -> z) &&
       circle -> y < (long) camera -> y + (long) camera -> z + (long) (2 * circle -> z) &&
       circle -> y > (long) camera -> y - (long) (2 * circle -> z)){
      // Creating a temporary and transparent surface
      struct surface *surf = new_surface((long) camera -> next, (long) camera -> down);
      XSetForeground(_dpy, _mask_gc, 0l);
      XFillRectangle(_dpy, surf -> mask, _mask_gc, 0, 0, surf -> width, surf -> height);

      // Drawing the circle in the surface
      XSetForeground(_dpy, _gc, color);
      XDrawArc(_dpy, surf -> pix, _gc, x - width / 2, y - height / 2, width, height, 0, 23040);
      XFillArc(_dpy, surf -> pix, _gc, x - width / 2, y - height / 2, width, height, 0, 23040);

      // Drawing the circle in the transparency map
      XSetForeground(_dpy, _mask_gc, ~0l);
      XDrawArc(_dpy, surf -> mask, _mask_gc, x - width / 2, y - height / 2, width, height, 0, 23040);
      XFillArc(_dpy, surf -> mask, _mask_gc, x - width / 2, y - height / 2, width, height, 0, 23040);

      // Blitting the surface in the screen
      blit_surface(surf, window, 0, 0, surf -> width, surf -> height,
		   (long) camera -> previous, (long) camera -> top);
      destroy_surface(surf);
    }
  }
  else
    fill_ellipse(x, y, width, height, color);
}

This function draws and fills a circle passed as argument using the referential stored by the camera passed as the first argument and the color passed as third argument.

This function returns nothing.

void
film_rectangle(camera *cam, rectangle *rect, unsigned color)

void film_rectangle(struct vector4 *camera, struct vector4 *rectangle, unsigned color){
  int x, y, height, width;
  x = (int) (((rectangle -> x - camera -> x) / camera -> w) * window_width);
  y = (int) (((rectangle -> y - camera -> y) / camera -> z) * window_height);
  height = (int) ((rectangle -> z / camera -> z) * window_height);
  width = (int) ((rectangle -> w / camera -> w) * window_width);

  if(camera -> previous != NULL || camera -> next != NULL){
    limited_camera ++;
    x = (int) ((float) x * ((float) (long) camera -> next) /
               (float) window_width);
    width = (int) ((float) width * ((float) (long) camera -> next) /
                   (float) window_width);
  }
  if(camera -> top != NULL || camera -> down != NULL){
    limited_camera ++;
    y = (int) ((float) y * ((float) (long) camera -> down) /
               (float) window_height);
    height = (int) ((float) height * ((float) (long) camera -> down) /
                    (float) window_height);
  }
  if(limited_camera){
    if(rectangle -> x + rectangle -> w > camera -> x &&
       rectangle -> x < camera -> x + camera -> w &&
       rectangle -> y + rectangle -> z > camera -> y &&
       rectangle -> y < camera -> y + camera -> z){
      // If we are here, the rectangle appears in the camera
      // Creating a temporary and transparent surface
      struct surface *surf = new_surface((long) camera -> next,
                                         (long) camera -> down);
      XSetForeground(_dpy, _mask_gc, 0l);
      XFillRectangle(_dpy, surf -> mask, _mask_gc, 0, 0, surf -> width,
                     surf -> height);

      // Drawing the rectangle in the surface
      XSetForeground(_dpy, _gc, color);
      XDrawRectangle(_dpy, surf -> pix, _gc, x, y, width, height);

      // Drawing the circle in the transparency map
      XSetForeground(_dpy, _mask_gc, ~0l);
      XDrawRectangle(_dpy, surf -> mask, _mask_gc, x, y, width, height);

      // Blitting the surface in the screen
      blit_surface(surf, window, 0, 0, surf -> width, surf -> height,
		   (long) camera -> previous, (long) camera -> top);
      destroy_surface(surf);
    }
  }
  else
  draw_rectangle(x, y, width, height, color);
}

This function draws the rectangle passed as argument using the referential stored in the camera (first argument) with the color passed as the third argument.

This function returns nothing.

void
film_fullrectangle(camera *cam, rectangle *cam, unsigned color)

void film_fullrectangle(struct vector4 *camera, struct vector4 *rectangle, unsigned color){
  int x, y, height, width;
  x = (int) (((rectangle -> x - camera -> x) / camera -> w) * window_width);
  y = (int) (((rectangle -> y - camera -> y) / camera -> z) * window_height);
  height = (int) ((rectangle -> z / camera -> z) * window_height);
  width = (int) ((rectangle -> w / camera -> w) * window_width);

  if(camera -> previous != NULL || camera -> next != NULL){
    limited_camera ++;
    x = (int) ((float) x * ((float) (long) camera -> next) /
               (float) window_width);
    width = (int) ((float) width * ((float) (long) camera -> next) /
                   (float) window_width);
  }
  if(camera -> top != NULL || camera -> down != NULL){
    limited_camera ++;
    y = (int) ((float) y * ((float) (long) camera -> down) /
               (float) window_height);
    height = (int) ((float) height * ((float) (long) camera -> down) /
                    (float) window_height);
  }

  if(limited_camera){
    if(rectangle -> x + rectangle -> w > camera -> x &&
       rectangle -> x < camera -> x + camera -> w &&
       rectangle -> y + rectangle -> z > camera -> y &&
       rectangle -> y < camera -> y + camera -> z){
      // If we are here, the rectangle appears in the camera
      // Creating a temporary and transparent surface
      struct surface *surf = new_surface((long) camera -> next,
                                         (long) camera -> down);
      XSetForeground(_dpy, _mask_gc, 0l);
      XFillRectangle(_dpy, surf -> mask, _mask_gc, 0, 0, surf -> width,
                     surf -> height);

      // Drawing the rectangle in the surface
      XSetForeground(_dpy, _gc, color);
      XDrawRectangle(_dpy, surf -> pix, _gc, x, y, width, height);
      XFillRectangle(_dpy, surf -> pix, _gc, x, y, width, height);

      // Drawing the circle in the transparency map
      XSetForeground(_dpy, _mask_gc, ~0l);
      XDrawRectangle(_dpy, surf -> mask, _mask_gc, x, y, width, height);
      XFillRectangle(_dpy, surf -> mask, _mask_gc, x, y, width, height);

      // Blitting the surface in the screen
      blit_surface(surf, window, 0, 0, surf -> width, surf -> height,
		   (long) camera -> previous, (long) camera -> top);
      destroy_surface(surf);
    }
  }
  else
  fill_rectangle(x, y, width, height, color);
}

This function draws and fills the rectangle passed as second argument using the referential stored in the camera (first argument) with the color passed as the third argument.

This function returns nothing.

void
film_fullpolygon(camera *cam, polygon *poly, unsigned color)

void film_fullpolygon(struct vector4 *camera, struct vector2 *polygon, unsigned color){
  struct vector2 *current_vertex = polygon;
  XPoint *points;
  int number_of_points = 0;

  XSetFillRule(_dpy, _gc, WindingRule);

  if(polygon == NULL || polygon -> next == polygon)
    return;

  if(camera -> previous != NULL || camera -> next != NULL)
    limited_camera = 1;

  // Discovering the number of points
  do{
    number_of_points ++;
    current_vertex = current_vertex -> next;
  }while(current_vertex != polygon);

  // Allocating space for the XPoints
  points = (XPoint *) malloc(sizeof(XPoint) * number_of_points);

  //Getting thew points coordinates
  number_of_points = 0;
  current_vertex = polygon;
  do{
    points[number_of_points].x =  (int) (((current_vertex -> x - camera -> x) / camera -> w) * window_width);
    points[number_of_points].y =  (int) (((current_vertex -> y - camera -> y) / camera -> z) * window_height);
    number_of_points ++;
    current_vertex = current_vertex -> next;
  }while(current_vertex != polygon);
// Correcting values if we are under a limited camera
  if(limited_camera){
    number_of_points = 0;
    current_vertex = polygon;
    do{
      points[number_of_points].x = (int) ((float) points[number_of_points].x *
                                          ((float) (long) camera -> next) /
                                          (float) window_width);
      points[number_of_points].y = (int) ((float) points[number_of_points].y *
                                          ((float) (long) camera -> down) /
                                          (float) window_height);

      number_of_points ++;
      current_vertex = current_vertex -> next;
    }while(current_vertex != polygon);

    // Creating a temporary and transparent surface
    struct surface *surf = new_surface((long) camera -> next,
                                       (long) camera -> down);
    XSetFillRule(_dpy, _mask_gc, WindingRule);
    XSetForeground(_dpy, _mask_gc, 0l);
    XFillRectangle(_dpy, surf -> mask, _mask_gc, 0, 0, surf -> width,
                   surf -> height);

    // Drawing the polygon in the surface
    XSetForeground(_dpy, _gc, color);
    XFillPolygon(_dpy, surf -> pix, _gc, points, number_of_points, Complex,
               CoordModeOrigin);


    // Drawing the polygon in the transparency map
    XSetForeground(_dpy, _mask_gc, ~0l);
    XFillPolygon(_dpy, surf -> mask, _mask_gc, points, number_of_points,
                 Complex, CoordModeOrigin);

    // Blitting the surface in the screen
    blit_surface(surf, window, 0, 0, surf -> width, surf -> height,
                 (long) camera -> previous, (long) camera -> top);
    destroy_surface(surf);
  }
  else{
    XSetForeground(_dpy, _gc, color);
    XFillPolygon(_dpy, _w, _gc, points, number_of_points, Complex, CoordModeOrigin);
  }
  free(points);
}

This functions draws and fills the polygon passad as argument using the coordinates stored in the camera (first argument) with the color passed as third argument.

This function returns nothing.

void
film_polygon(camera *cam, polygon *poly, unsigned color)

This functions draws the polygon passed as second argument using the coordinates stored in the camera (first argument) with the color passed as the third argument.

This function returns nothing.

void
flush(void)

 void flush(void){
  XdbeSwapInfo info;
  info.swap_window = _w;
  info.swap_action = XdbeCopied;
  XdbeSwapBuffers(_dpy, &info, 1);
  XFlush(_dpy);
}

Usually, when you draw something in the screen, the changes aren't applied immediately. The commands are queued, and even after execution, they change only a temporary buffer, not the actual screen. The screen is updated only when the functions flush or weaver_rest are called. The first can be called anywhere, while the second should be called only once inside a main loop.

This function returns nothing.

void
get_input(void)

void get_input(void){
  XEvent event;
  KeySym pressed_key, released_key;
  mouse.changed = 0;

  while(XPending(_dpy)){
    XNextEvent(_dpy, &event);

    if(event.type == KeyPress){ // KEYBOARD EVENT
      keyboard[ANY] += 1;
      pressed_key = XLookupKeysym(&event.xkey, 0);

      // Treating special cases first
      if(pressed_key == LEFT_SHIFT || pressed_key == RIGHT_SHIFT)
	keyboard[SHIFT] += 1;
      if(pressed_key == LEFT_CTRL || pressed_key == RIGHT_CTRL)
	keyboard[CTRL] += 1;
      if(pressed_key == LEFT_ALT || pressed_key == RIGHT_ALT)
	keyboard[ALT] += 1;

      keyboard[pressed_key] += 1; //Default behaviour
    }
    else if(event.type == KeyRelease){
      released_key = XLookupKeysym(&event.xkey, 0);
      keyboard[ANY] = 0;

      // Some special cases
      if(released_key == LEFT_SHIFT || released_key == RIGHT_SHIFT)
	keyboard[SHIFT] = 0;
      if(released_key == LEFT_CTRL || released_key == RIGHT_CTRL)
	keyboard[CTRL] = 0;
      if(released_key == LEFT_ALT || released_key == RIGHT_ALT)
	keyboard[ALT] = 0;


      keyboard[released_key] = 0; // Default behaviour
    }
    else if(event.type == ButtonPress){ //MOUSE EVENT
      if(! mouse.pressed){
	mouse.pressed = 1;
	mouse.changed = 1;
      }
      mouse.x = event.xbutton.x;
      mouse.y = event.xbutton.y;
    }
    else if(event.type == ButtonRelease){
      if(mouse.pressed){
	mouse.pressed = 0;
	mouse.changed = 1;
      }
      mouse.x = event.xbutton.x;
      mouse.y = event.xbutton.y;
    }
    else if(event.type == MotionNotify){
      mouse.x = event.xmotion.x;
      mouse.y = event.xmotion.y;
    }
  }
}

This function is responsible for store information about the input. Which keys were pressed, if the mouse changed, which keys were released, if the player clicked with the mouse...

As games are event-oriented programs, this function probably will be called every main loop iteration.

Basically, this function updates the keyboard and mouse variables.

This function returns nothing.

void
hide_cursor(void)

void hide_cursor(void){
  Colormap cmap;
  Cursor no_ptr;
  XColor black, dummy;
  static char bm_no_data[] = {0, 0, 0, 0, 0, 0, 0, 0};
  Pixmap bm_no;

  cmap = DefaultColormap(_dpy, DefaultScreen(_dpy));
  XAllocNamedColor(_dpy, cmap, "black", &black, &dummy);
  bm_no = XCreateBitmapFromData(_dpy, _w, bm_no_data, 8, 8);
  no_ptr = XCreatePixmapCursor(_dpy, bm_no, bm_no, &black, &black, 0, 0);

  XDefineCursor(_dpy, _w, no_ptr);
  XFreeCursor(_dpy, no_ptr);
  if(bm_no != None)
    XFreePixmap(_dpy, bm_no);
  XFreeColors(_dpy, cmap, &black.pixel, 1, 0);
}

This function hides the cursor in the screen. In fact, it works setting the cursor to an empty bitmap.

This function returns nothing.

void
limit_camera(camera *cam, int x, int y, int width, int height)

void limit_camera(struct vector4 *camera, int x, int y, int width, int height){
  camera -> previous = (struct vector4 *) (long) x;
  camera -> top = (struct vector4 *) (long) y;
  camera -> next = (struct vector4 *) (long) width;
  camera -> down = (struct vector4 *) (long) height;
}

By default, a camera will draw all the visible elements using the whole screen. This function changes the default and limits the are in wich a given camera can draw.

This functions makes the camera "cam" draws only in the rectangle whose upper left vertex is the pixel ("x", "y") in the screen and whose width is "width" pixels and whose height is "height" pixels.

This function returns nothing.

void
may_the_weaver_sleep(void)

This function frees all the memory allocated and all the changes made by the awake_the_weaver function. When you finish to use all the Weaver resourses, you should call this function.

When you use the Weaver Framework, this function is placed automaticly in the end of the main function.

This function returns nothing.

void
move_circle(circle *circ, float x, float y)

void move_circle(struct vector3 *circ, float x, float y){
  if(circ == NULL)
    return;
  circ -> x += x;
  circ -> y += y;
}

This moves the circle "circ" at "x" units in the X-axis and "y" units in the Y-axis.

It's the programmer's responsability to check for overflows. If an overflow happens, probably the circle will teleport itself for some strange location.

This function returns nothing.

void
move_polygon(struct vector2 *poly, float x, float y)

void move_polygon(struct vector2 *poly, float x, float y){
  struct vector2 *first_vertex, *current_vertex;
  if(poly == NULL)
    return;
  first_vertex = current_vertex = poly;
  do{
    current_vertex -> x += x;
    current_vertex -> y += y;
    current_vertex = current_vertex -> next;
  }while(current_vertex != first_vertex);
}

This moves the polygon "poly" "x" coordinates in the X-axis and "y" coordinates in the Y-axis. It works moving all the vertices of a polygon.

Overflow checking is the programmer's responsability. If an overflow happens, a weird undefined behaviour can happen. Probably the polygon will become huge and/or deformed for some moments or permanently.

This function returns nothing.

camera *
new_camera(float x, float y, float width, float height)

#define new_camera(x, y, width, height) new_vector4(width, x, y, height)

This allocates space in memory for a new camera and returns a pointer to it's address. If the process fails, the function returns NULL instead.

The arguments represent a rectangle that's the are covered by the camera. The (x, y) are the rectangle's coordinates and the other arguments are the rectangle's width and height.

Every memory allocated for a camera should be freed with free or destroy_camera functions.

camera *
new_camera_h(float x, float y, float height)

#define new_camera_h(x, y, height) new_vector4(height *        \
                                     ((float) window_width /   \
                                     (float) window_height),   \
                                     x, y, height)

This allocates space for a new camera positioned in the coordinates (x, y) and whose height is passed as the third argument. The camera's width is calculed automaticly according with the screen's resolution. This prevents images distortions.

Every memory allocated for a camera should be freed with free or destroy_camera functions.

camera *
new_camera_w(float x, float y, float width)

#define new_camera_w(x, y, width) new_vector4(width, x, y, width *    \
                                             ((float) window_height / \
                                             (float) window_width))

This allocates space for a new camera positioned in the coordinates (x, y) and whose width is passed as the third argument. The camera's height is calculed automaticly according with your screen's resolution. This prevents images distortions.

Every memory allocated for a camera should be freed with free or destroy_camera functions.

circle *
new_circle(float x, float y, float radius)

#define new_circle(x, y, z) new_vector3(x, y, z)

This allocates space in memory for a new circle and return a pointer to it's address. If no more memory is available, it returns NULL instead.

Every allocated circle shall be destroyed with destroy_circle or free.

surface *
new_image(char *image_name)

struct surface *new_image(char *file){
  int rc;
  double default_display_exponent;
  FILE *infile;
  char *path = (char *) malloc(strlen(file)+60);
  path[0] = '\0';

  struct surface *my_surf;
  _display_exponent = default_display_exponent = 2.2;

  strcat(path, "/usr/share/games/DUMMY/images/");
  strcat(path, file);
  if(!(infile = fopen(path, "rb"))){
    path[0] = '\0';
    strcat(path, "images/");
    strcat(path, file);
    if(!(infile = fopen(path, "rb")))
      return NULL;
  }

  if((rc = _readpng_init(infile, (long *) &_image_width, (long *) &_image_height)) != 0)
    return NULL;

  if(_readpng_get_bgcolor(&_bg_red, &_bg_green, &_bg_blue) > 1){
    return NULL;
  }
  image_data = _readpng_get_image(_display_exponent, &_image_channels,
                                 &_image_rowbytes);
  my_surf = new_surface(_image_width, _image_height);
  _display_image(my_surf, 0, 0);
  fclose(infile);
  png_destroy_read_struct(&_png_ptr, &_info_ptr, NULL);
  free(image_data);

  return my_surf;
}

First this function search in the directory "/usr/share/games/YOURGAME/images" for the PNG image that you passed as argument. If the game is installed, it should find the image. Else, it searches for the directory "images/" in your current directory and try to find it there. Doing this, it'll find the image when the game is installed, and also when you're still developing your game.

Note that if you install the game and then change some image in the images/ directory, to see the changes, you should install the game again.

If no image is found, or some error happens while decoding the image, the function returns NULL. Else, it returns a surface with the given image. The transparency mask is built according with the value of transparent variable. If a given pixel has the same value than this variable, the function considers it transparent.

This function stills doesn't support the alpha channel in PNG images.

polygon *
new_polygon(int vertices, ...)

struct vector2 *new_polygon(int number_of_vertices, ...){
  struct vector2 *new_vector = NULL;
  struct vector2 *first_vector = NULL, *previous_vector;
  va_list args;
  float x, y;
  int vertices = number_of_vertices;

  previous_vector = NULL;

  va_start(args, number_of_vertices);
  for(;number_of_vertices > 0; number_of_vertices --){
    x = (float) va_arg(args, double);
    y = (float) va_arg(args, double);
    new_vector = new_vector2(x, y);
    if(new_vector == NULL){
      if(previous_vector != NULL){
        previous_vector -> next = first_vector;
        first_vector -> previous = previous_vector;
        destroy_polygon(first_vector);
      }
      return new_vector;
    }
    if(previous_vector != NULL)
      connect_vector2(previous_vector, new_vector);
    else
      first_vector = new_vector;
    previous_vector = new_vector;
  }
  if(vertices > 0){
    new_vector -> next = first_vector;
    first_vector -> previous = new_vector;
  }
  return first_vector;
}

This function allocates the space in memory for a new polygon. If there's no space, the function gives up and return NULL.

The first argument is the number o vertices. Then, the function expects to find 2*N other arguments, being N the number of vertices, because each vertex have 2 float numbers that represent it's coordinates.

The order in wich you pass the coordinates is important. This is the order in which the vertices will be drawn and connected. Here's some examples:

new_polygon(0); // Nonsense. Returns NULL
new_polygon(1, 2.0, 3.0); // A single point in coordinate(2.0, 3.0)
new_polygon(5, 0.0, 0.0, -1.0, 1.0, 1.0, 2.0, 3.0, 1.0, 2.0, 0.0); // Pentagon
new_polygon(5, 0.0, 0.0, 1.0, 2.0, 2.0, 0.0, -1.0, 1.0, 3.0, 1.0); // Pentagram

This way, you can create simple or complex, concave or convex polygons. To free the memory allocated, use destroy_polygon. The function free doesn't work here because a polygon isn't (in most cases) a single vector2, but a set of interconnected vectors.

rectangle *
new_rectangle(float x, float y, float width, float height)

#define new_rectangle(x, y, w, z) new_vector4(w, x, y, z)

This function allocates space for a new rectangle with the width and height passed as arguments and whose upper left vertex is in the coordinate (x, y) also passed as argument. The function returns a pointer for the new rectangle. If the process fails, it returns NULL instead.

Every allocated rectangle should be freed with free or destroy_rectangle functions.

struct surface *
new_surface(int width, int height)

struct surface *new_surface(int width, int height){
  struct surface *my_surf;
  if(width <= 0 || height <= 0)
    return NULL;
  my_surf = (struct surface *) malloc(sizeof(struct surface));
  if(my_surf != NULL){
    my_surf -> pix = XCreatePixmap(_dpy, _w, width, height, _depth);
    my_surf -> width = width;
    my_surf -> height = height;
    my_surf -> mask = XCreatePixmap(_dpy, _w, width, height, 1ul);
    if(_mask_gc == None)
      _mask_gc = XCreateGC(_dpy, my_surf -> mask, 0, NULL);
    XSetForeground(_dpy, _mask_gc, ~0l);
    XFillRectangle(_dpy, my_surf -> mask, _mask_gc, 0, 0, my_surf -> width,
      my_surf -> height);
  }
  return my_surf;
}

This function receives as argument a width and height in pixels and returns a pointer to an empty surface with the given size.

If the function fails while allocating new space in the memory, it returns NULL instead.

struct vector2 *
new_vector2(float x, float y)

struct vector2 *new_vector2(float x, float y){
  struct vector2 *vector;
  vector = (struct vector2 *) malloc(sizeof(struct vector2));
  if(vector != NULL){
    vector -> x = x;
    vector -> y = y;
    vector -> previous = vector -> next = NULL;
  }
  return vector;
}

This creates a new struct vector2 whose "x" and "y" values are defined by the values passed as arguments. The pointers "previous" and "next" are set to NULL. Then, it returns a pointer for the new vector. If this process fails for some reason, it returns NULL.

Every created vector shall be destroyed with free or destroy_vector2 functions.

struct vector3 *
new_vector3(float x, float y, float z)

struct vector3 *new_vector3(float x, float y, float z){
  struct vector3 *new_vector;
  new_vector = (struct vector3 *) malloc(sizeof(struct vector3));
  if(new_vector != NULL){
    new_vector -> previous = new_vector -> next = new_vector -> top = NULL;
    new_vector -> x = x;
    new_vector -> y = y;
    new_vector -> z = z;
  }
  return new_vector;
}

This creates a new struct vector3 whose "x", "y" and "z" values are defined by those passed as arguments. The pointers "previous", "next" and "top" are set to NULL. Then, it returns a pointer for the new vector. If this process fails, the function returns NULL.

Every created vector3 shall be destroyed with free or destroy_vector3 functions.

struct vector4 *
new_vector4(float w, float x, float y, float z)

struct vector4 *new_vector4(float w, float x, float y, float z){
  struct vector4 *vector;
  vector = (struct vector4 *) malloc(sizeof(struct vector4));
  if(vector != NULL){
    vector -> previous = vector -> next = vector -> top =
      vector -> down = NULL;
    vector -> w = w;
    vector -> x = x;
    vector -> y = y;
    vector -> z = z;
  }
  return vector;
}

This creates a new struct vector4 whose "w", "x", "y" and "z" values are defined by those passed as arguments. The pointers "previous", "next", "top" and "down" are set to NULL. Then, it returns a pointer for the new vector. If this process fails, the function returns NULL.

Every created vector4 shall be destroyed with free or destroy_vector4 functions.

void
play_music(char *file)

void play_music(char *file){
  if(_music)
    kill(_music, 9);
  if(!(_music = fork())){
    for(;;)
      _play_soundfile(file, "music/");
  }
}

This function creates a new thread that plays an Ogg Vorbis file.

The new thread searches for the file in "/usr/share/games/YOURGAME/music/". If the game is installed, the file is probably there. If not, it searches for the sound inside the "music" directory in your current directory.

The new thread never stops to play the music. When the music is over, it stars to play it again from the beginning. If you wish to stop the music, use the stop_music function.

This function returns nothing.

void
play_sound(char *file)

void play_sound(char *file){
  if(!fork()){
    _play_soundfile(file, "sound/");
    exit(0);
  }
}

This function creates a new thread that plays an Ogg Vorbis file.

The new thread searches for the file in "/usr/share/games/YOURGAME/sound/". If the game is installed, the file is probably there. If not, it searches for the sound inside the "sound" directory in your current directory.

The new thread open doesn't communicate with the main program. The sound is played until the end or until the end of the program. This function was created to handle only minor sound effects, nothing long like a music.

This function returns nothing.

void
rotate_circle(struct vector3 *circ, float x, float y, float rad)

void rotate_circle(struct vector3 *circ, float x, float y, float rad){
  long double new_x, new_y;
  if(circ == NULL)
    return;
  new_x = (long double) circ -> x - (long double) x;
  new_y = (long double) circ -> y - (long double) y;
  new_x = new_x * cosl((long double) rad) - new_y * sinl((long double) rad);
  new_y = ((long double) circ -> x - (long double) x) *
    sinl((long double) rad) + new_y * cosl((long double) rad);
  circ -> x = (float) (new_x + (long double) x);
  circ -> y = (float) (new_y + (long double) y);
}

This applies a linear transformation in the circle's center coordinates. This makes the circle "circ" rotates around the axis (x, y) at "rad" radians.

It's the programmer's responsability to check for overflows. If an overflow happens, probably the circle will teleport itself for some strange location.

This function returns nothing.

void
rotate_polygon(struct vector2 *poly, float x, float y, float rad)

void rotate_polygon(struct vector2 *poly, float x, float y, float rad){
  long double new_x, new_y;
  struct vector2 *first_vector, *current_vector;
  if(poly == NULL)
    return;
  first_vector = current_vector = poly;
  do{
    new_x = (long double) current_vector -> x - (long double) x;
    new_y = (long double) current_vector -> y - (long double) y;
    new_x =  new_x * cosl((long double) rad) - new_y * sinl((long double) rad);
    new_y = ((long double) current_vector -> x - (long double) x) *
      sinl((long double) rad) + new_y * cosl((long double) rad);
    current_vector -> x = (float) (new_x + (long double) x);
    current_vector -> y = (float) (new_y + (long double) y);
    current_vector = current_vector -> next;
  }while(current_vector != first_vector);
}

Rotates the polygon "poly" at "rad" radians in the axis (x, y). It changes all the coordinates of polygon's vertices doing a linear transformation.

It's the programmer's responsability to check for overflows. If an overflow happens, probably the polygon will be severely deformed temporarily or permanently.

This function returns nothing.

void
stop_music(void)

void stop_music(void){
  if(_music)
    kill(_music, 9);
}

This function checks if there's some music playing. If so, it sends a signal that kills the thread that is playing the music.

This function returns nothing.

void
weaver_rest(long nanoseconds)

void weaver_rest(long nanoseconds){
  XdbeSwapInfo info;
  info.swap_window = _w;
  info.swap_action = XdbeCopied;
  struct timespec req = {0, nanoseconds};
  nanosleep(&req, NULL);
  _b_frame.tv_sec = current_time.tv_sec;
  _b_frame.tv_usec = current_time.tv_usec;
  gettimeofday(&current_time, NULL);
  fps = 1000000 / (1000000 * (current_time.tv_sec - _b_frame.tv_sec) + current_time.tv_usec - _b_frame.tv_usec);
  if(fps == 0) fps = 1;
  XdbeSwapBuffers(_dpy, &info, 1);
}

This function pauses the program for the number of nanoseconds passed as argument. It's very usefull to prevent your program to consume 100% of your CPU cicles inside the main loop.

If you use the Weaver framework, this function is positioned inside the program's main loop automaticly.

Remember that 1,000,000,000 nanoseconds = 1 second.

This function returns nothing.

void
zoom_camera(struct vector4 *camera, float zoom)

void zoom_camera(struct vector4 *cam, float zoom){
  float x, y;
  // Storing the central point
  x = cam -> x + (cam -> w / 2);
  y = cam -> y + (cam -> z / 2);
  // Zooming
  cam -> w /= zoom;
  cam -> z /= zoom;
  // Restoring the central point
  cam -> x = x - (cam -> w / 2);
  cam -> y = y - (cam -> z / 2);
}

This function is used to zooms in and out a camera. The second argument passed is how bigger you wish the images. A 2.0 shows all the objects with double size. A 0.5 makes everything half-sized.

Please, don't pass 0 or negative numbers to the function.

This function returns nothing.

Global Variables

surface *background;

When you erase some element in the screen, the element is replaced by pixels from the background surface.

By default, the background is entirely black.

struct timeval current_time

This variable stores the current time with microsecond precision. To get the current time in seconds, access current_time -> tv_sec; and to get the microsecond count, access current_time -> tv_usec.

This variable is initialized in awake_the_weaver function and it's always updated in the weaver_rest function.

int fps

This variable stores in how many frames per second the game is running. It's updated automaticly by weaver_rest function.

int keyboard[KEYS]

This is the keyboard buffer. It's a vector with as many positions as recogniseable keys in your keyboard. By default, all positions have the value 0. When you presses a key, the key's correspondent position in the vector has it's value incremented by 1, each frame. When you release the key, it's value becames 0.

This variable is updated every turn by get_input function.

struct{ int pressed, changed, x, y; } mouse

This variable stores your mouse's information. By default, "pressed" and "changed" values are 0. And "x", "y" always stores the mouse's coordinates. In the frame where you change the mouse's position, "changed" value becomes 1. In the frame where you click with the mouse, "clicked" value becomes 1.

This variable is updated every frame by get_input function.

unsigned long transparent_color

By default this variable value is 0x00029a. When you create a new surface from a PNG image, for example, all the pixels with this value will be considered transparent. You can change this variable to other values if you wish. This variable is initialized in awake_the_weaver function.

surface *window

This surface represents our window. Every surface blitted in the window surface is blitted in the screen.

This is an unusual surface because you can't use it's mask. A window doesn't have a mask pixmap. This variable is initialized in awake_the_weaver function.

int window_height

This variable stores the window height in pixels. This variable is initialized in awake_the_weaver function.

int window_width

This variable stores the window width in pixels. This variable is initialized in awake_the_weaver function.

Macros

// Defining colors...
#define NOT_IMPORTANT       0x000000
#define BLACK               0x000000
#define BLUE                0x0000ff
#define GREEN               0x00ff00
#define CYAN                0x00ffff
#define BROWN               0x964b00
#define BEIGE               0xf5f5dc
#define RED                 0xff0000
#define YELLOW              0xffff00
#define WHITE               0xffffff

// Number of keys watched
#define KEYS 0xffff+0x4

// Position of each key
#define UP          XK_Up
#define RIGHT       XK_Right
#define DOWN        XK_Down
#define LEFT        XK_Left
#define PLUS        XK_KP_Add
#define MINUS       XK_KP_Subtract
#define SHIFT       KEYS-1
#define CTRL        KEYS-2
#define ESC         XK_Escape
#define A           XK_a
#define S           XK_s
#define D           XK_d
#define W           XK_w
#define ENTER       XK_Return
#define LEFT_CTRL   XK_Control_L
#define RIGHT_CTRL  XK_Control_R
#define F1          XK_F1
#define ANY         KEYS-3
#define ALT         KEYS-4
#define F2          XK_F2
#define F3          XK_F3
#define F4          XK_F4
#define F5          XK_F5
#define F6          XK_F6
#define F7          XK_F7
#define F8          XK_F8
#define F9          XK_F9
#define F10         XK_F10
#define F11         XK_F11
#define F12         XK_F12
#define BACKSPACE   XK_BackSpace
#define TAB         XK_Tab
#define PAUSE       XK_Pause
#define DELETE      XK_Delete
#define SCROLL_LOCK XK_Scroll_Lock
#define HOME        XK_Home
#define PAGE_UP     XK_Page_Up
#define PAGE_DOWN   XK_Page_Down
#define END         XK_End
#define INSERT      XK_Insert
#define NUM_LOCK    XK_Num_Lock
#define ZERO        XK_KP_0
#define ONE         XK_KP_1
#define TWO         XK_KP_2
#define THREE       XK_KP_3
#define FOUR        XK_KP_4
#define FIVE        XK_KP_5
#define SIX         XK_KP_6
#define SEVEN       XK_KP_7
#define EIGHT       XK_KP_8
#define NINE        XK_KP_9
#define LEFT_SHIFT  XK_Shift_L
#define RIGHT_SHIFT XK_Shift_R
#define CAPS_LOCK   XK_Caps_Lock
#define LEFT_ALT    XK_Alt_L
#define RIGHT_ALT   XK_Alt_R
#define Q           XK_q
#define E           XK_e
#define R           XK_r
#define T           XK_t
#define Y           XK_y
#define U           XK_u
#define I           XK_i
#define O           XK_o
#define P           XK_p
#define F           XK_f
#define G           XK_g
#define H           XK_h
#define J           XK_j
#define K           XK_k
#define L           XK_l
#define Z           XK_z
#define X           XK_x
#define C           XK_c
#define V           XK_v
#define B           XK_b
#define N           XK_n
#define M           XK_m

XHTML 1.1 válido! CSS válido!