home *** CD-ROM | disk | FTP | other *** search
/ RISCWORLD 7 / RISCWORLD_VOL7.iso / Software / Issue6 / SDL.ZIP / !ballfield / c / ballfield
Encoding:
Text File  |  2007-03-15  |  9.5 KB  |  515 lines

  1. /*
  2.  * "Ballfield"
  3.  *
  4.  *   (C) David Olofson <david@olofson.net>, 2002, 2003
  5.  *
  6.  * This software is released under the terms of the GPL.
  7.  *
  8.  * Contact author for permission if you want to use this
  9.  * software, or work derived from it, under other terms.
  10.  */
  11.  
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <math.h>
  15.  
  16. #include <SDL/SDL.h>
  17. #include <SDL/SDL_image.h>
  18.  
  19. #include "ballfield.h"
  20.  
  21.  
  22. /*----------------------------------------------------------
  23.     General tool functions
  24. ----------------------------------------------------------*/
  25.  
  26. /*
  27.  * Bump areas of low and high alpha to 0% or 100%
  28.  * respectively, just in case the graphics contains
  29.  * "alpha noise".
  30.  */
  31. SDL_Surface *clean_alpha(SDL_Surface *s)
  32. {
  33.     SDL_Surface *work;
  34.     SDL_Rect r;
  35.     Uint32 *pixels;
  36.     int pp;
  37.     int x, y;
  38.  
  39.     work = SDL_CreateRGBSurface(SDL_SWSURFACE, s->w, s->h,
  40.             32, 0xff000000, 0x00ff0000, 0x0000ff00,
  41.             0x000000ff);
  42.     if(!work)
  43.         return NULL;
  44.  
  45.     r.x = r.y = 0;
  46.     r.w = s->w;
  47.     r.h = s->h;
  48.     if(SDL_BlitSurface(s, &r, work, NULL) < 0)
  49.     {
  50.         SDL_FreeSurface(work);
  51.         return NULL;
  52.     }
  53.  
  54.     SDL_LockSurface(work);
  55.     pixels = work->pixels;
  56.     pp = work->pitch / sizeof(Uint32);
  57.     for(y = 0; y < work->h; ++y)
  58.         for(x = 0; x < work->w; ++x)
  59.         {
  60.             Uint32 pix = pixels[y*pp + x];
  61.             switch((pix & 0xff) >> 4)
  62.             {
  63.               case 0:
  64.                 pix = 0x00000000;
  65.                   break;
  66.               default:
  67.                   break;
  68.               case 15:
  69.                 pix |= 0xff;
  70.                   break;
  71.             }
  72.             pixels[y*pp + x] = pix;
  73.         }
  74.     SDL_UnlockSurface(work);
  75.  
  76.     return work;
  77. }
  78.  
  79.  
  80. /*
  81.  * Load and convert an antialiazed, zoomed set of sprites.
  82.  */
  83. SDL_Surface *load_zoomed(char *name, int alpha)
  84. {
  85.     SDL_Surface *sprites;
  86.     SDL_Surface *temp = IMG_Load(name);
  87.     if(!temp)
  88.         return NULL;
  89.  
  90.     sprites = temp;
  91.     SDL_SetAlpha(sprites, SDL_RLEACCEL, 255);
  92.     temp = clean_alpha(sprites);
  93.     SDL_FreeSurface(sprites);
  94.     if(!temp)
  95.     {
  96.         fprintf(stderr, "Could not clean alpha!\n");
  97.         return NULL;
  98.     }
  99.  
  100.     if(alpha)
  101.     {
  102.  
  103.         SDL_SetAlpha(temp, SDL_SRCALPHA|SDL_RLEACCEL, 0);
  104.         sprites = SDL_DisplayFormatAlpha(temp);
  105.     }
  106.     else
  107.     {
  108.         SDL_SetColorKey(temp, SDL_SRCCOLORKEY|SDL_RLEACCEL,
  109.                 SDL_MapRGB(temp->format, 0, 0, 0));
  110.         sprites = SDL_DisplayFormat(temp);
  111.     }
  112.     SDL_FreeSurface(temp);
  113.  
  114.     return sprites;
  115. }
  116.  
  117.  
  118. void print_num(SDL_Surface *dst, SDL_Surface *font, int x, int y, float value)
  119. {
  120.     char buf[16];
  121.     int val = (int)(value * 10.0);
  122.     int pos, p = 0;
  123.     SDL_Rect from;
  124.  
  125.     /* Sign */
  126.     if(val < 0)
  127.     {
  128.         buf[p++] = 10;
  129.         val = -val;
  130.     }
  131.  
  132.     /* Integer part */
  133.     pos = 10000000;
  134.     while(pos > 1)
  135.     {
  136.         int num = val / pos;
  137.         val -= num * pos;
  138.         pos /= 10;
  139.         if(p || num)
  140.             buf[p++] = num;
  141.     }
  142.  
  143.     /* Decimals */
  144.     if(val / pos)
  145.     {
  146.         buf[p++] = 11;
  147.         while(pos > 0)
  148.         {
  149.             int num = val / pos;
  150.             val -= num * pos;
  151.             pos /= 10;
  152.             buf[p++] = num;
  153.         }
  154.     }
  155.  
  156.     /* Render! */
  157.     from.y = 0;
  158.     from.w = 7;
  159.     from.h = 10;
  160.     for(pos = 0; pos < p; ++pos)
  161.     {
  162.         SDL_Rect to;
  163.         to.x = x + pos * 7;
  164.         to.y = y;
  165.         from.x = buf[pos] * 7;
  166.         SDL_BlitSurface(font, &from, dst, &to);
  167.     }
  168. }
  169.  
  170.  
  171.  
  172. /*----------------------------------------------------------
  173.     ballfield_t functions
  174. ----------------------------------------------------------*/
  175.  
  176. ballfield_t *ballfield_init(void)
  177. {
  178.     int i;
  179.     ballfield_t *bf = calloc(sizeof(ballfield_t), 1);
  180.     if(!bf)
  181.         return NULL;
  182.     for(i = 0; i < BALLS; ++i)
  183.     {
  184.         bf->points[i].x = rand() % 0x20000;
  185.         bf->points[i].y = rand() % 0x20000;
  186.         bf->points[i].z = 0x20000 * i / BALLS;
  187.         if(rand() % 100 > 80)
  188.             bf->points[i].c = 1;
  189.         else
  190.             bf->points[i].c = 0;
  191.     }
  192.     return bf;
  193. }
  194.  
  195.  
  196. void ballfield_free(ballfield_t *bf)
  197. {
  198.     int i;
  199.     for(i = 0; i < COLORS; ++i)
  200.         SDL_FreeSurface(bf->gfx[i]);
  201. }
  202.  
  203.  
  204. static int ballfield_init_frames(ballfield_t *bf)
  205. {
  206.     int i, j;
  207.     /*
  208.      * Set up source rects for all frames
  209.      */
  210.     bf->frames = calloc(sizeof(SDL_Rect), bf->gfx[0]->w);
  211.     if(!bf->frames)
  212.     {
  213.         fprintf(stderr, "No memory for frame rects!\n");
  214.         return -1;
  215.     }
  216.     for(j = 0, i = 0; i < bf->gfx[0]->w; ++i)
  217.     {
  218.         bf->frames[i].x = 0;
  219.         bf->frames[i].y = j;
  220.         bf->frames[i].w = bf->gfx[0]->w - i;
  221.         bf->frames[i].h = bf->gfx[0]->w - i;
  222.         j += bf->gfx[0]->w - i;
  223.     }
  224.     return 0;
  225. }
  226.  
  227.  
  228. int ballfield_load_gfx(ballfield_t *bf, char *name, unsigned int color)
  229. {
  230.     if(color >= COLORS)
  231.         return -1;
  232.  
  233.     bf->gfx[color] = load_zoomed(name, bf->use_alpha);
  234.     if(!bf->gfx[color])
  235.         return -2;
  236.  
  237.     if(!bf->frames)
  238.         return ballfield_init_frames(bf);
  239.  
  240.     return 0;
  241. }
  242.  
  243.  
  244. void ballfield_move(ballfield_t *bf, Sint32 dx, Sint32 dy, Sint32 dz)
  245. {
  246.     int i;
  247.     for(i = 0; i < BALLS; ++i)
  248.     {
  249.         bf->points[i].x += dx;
  250.         bf->points[i].x &= 0x1ffff;
  251.         bf->points[i].y += dy;
  252.         bf->points[i].y &= 0x1ffff;
  253.         bf->points[i].z += dz;
  254.         bf->points[i].z &= 0x1ffff;
  255.     }
  256. }
  257.  
  258.  
  259. void ballfield_render(ballfield_t *bf, SDL_Surface *screen)
  260. {
  261.     int i, j, z;
  262.  
  263.     /*
  264.      * Find the ball with the highest Z.
  265.      */
  266.     z = 0;
  267.     j = 0;
  268.     for(i = 0; i < BALLS; ++i)
  269.     {
  270.         if(bf->points[i].z > z)
  271.         {
  272.             j = i;
  273.             z = bf->points[i].z;
  274.         }
  275.     }
  276.  
  277.     /*
  278.      * Render all balls in back->front order.
  279.      */
  280.     for(i = 0; i < BALLS; ++i)
  281.     {
  282.         SDL_Rect r;
  283.         int f;
  284.         z = bf->points[j].z;
  285.         z += 50;
  286.         f = ((bf->frames[0].w << 12) + 100000) / z;
  287.         f = bf->frames[0].w - f;
  288.         if(f < 0)
  289.             f = 0;
  290.         else if(f > bf->frames[0].w - 1)
  291.             f = bf->frames[0].w - 1;
  292.         z >>= 7;
  293.         z += 1;
  294.         r.x = (bf->points[j].x - 0x10000) / z;
  295.         r.y = (bf->points[j].y - 0x10000) / z;
  296.         r.x += (screen->w - bf->frames[f].w) >> 1;
  297.         r.y += (screen->h - bf->frames[f].h) >> 1;
  298.         SDL_BlitSurface(bf->gfx[bf->points[j].c],
  299.             &bf->frames[f], screen, &r);
  300.         if(--j < 0)
  301.             j = BALLS - 1;
  302.     }
  303. }
  304.  
  305.  
  306.  
  307. /*----------------------------------------------------------
  308.     Other rendering functions
  309. ----------------------------------------------------------*/
  310.  
  311. /*
  312.  * Draw tiled background image with offset.
  313.  */
  314. void tiled_back(SDL_Surface *back, SDL_Surface *screen, int xo, int yo)
  315. {
  316.     int x, y;
  317.     SDL_Rect r;
  318.     if(xo < 0)
  319.         xo += back->w*(-xo/back->w + 1);
  320.     if(yo < 0)
  321.         yo += back->h*(-yo/back->h + 1);
  322.     xo %= back->w;
  323.     yo %= back->h;
  324.     for(y = -yo; y < screen->h; y += back->h)
  325.         for(x = -xo; x < screen->w; x += back->w)
  326.         {
  327.             r.x = x;
  328.             r.y = y;
  329.             SDL_BlitSurface(back, NULL, screen, &r);
  330.         }
  331. }
  332.  
  333.  
  334.  
  335. /*----------------------------------------------------------
  336.     main()
  337. ----------------------------------------------------------*/
  338.  
  339. int main(int argc, char* argv[])
  340. {
  341.     ballfield_t    *balls;
  342.     SDL_Surface    *screen;
  343.     SDL_Surface    *temp_image;
  344.     SDL_Surface    *back, *logo, *font;
  345.     SDL_Event    event;
  346.     int        bpp = 0,
  347.             flags = SDL_DOUBLEBUF | SDL_SWSURFACE,
  348.             alpha = 1;
  349.     int        x_offs = 0, y_offs = 0;
  350.     long        tick,
  351.             last_tick,
  352.             last_avg_tick;
  353.     double        t = 0;
  354.     float        dt;
  355.     int        i;
  356.     float        fps = 0.0;
  357.     int        fps_count = 0;
  358.     int        fps_start = 0;
  359.     float        x_speed, y_speed, z_speed;
  360.  
  361.     SDL_Init(SDL_INIT_VIDEO);
  362.  
  363.     atexit(SDL_Quit);
  364.  
  365.     for(i = 1; i < argc; ++i)
  366.     {
  367.         if(strncmp(argv[i], "-na", 3) == 0)
  368.             alpha = 0;
  369.         else if(strncmp(argv[i], "-nd", 3) == 0)
  370.             flags &= ~SDL_DOUBLEBUF;
  371.         else if(strncmp(argv[i], "-h", 2) == 0)
  372.         {
  373.             flags |= SDL_HWSURFACE;
  374.             flags &= ~SDL_SWSURFACE;
  375.         }
  376.         else if(strncmp(argv[i], "-f", 2) == 0)
  377.             flags |= SDL_FULLSCREEN;
  378.         else
  379.             bpp = atoi(&argv[i][1]);
  380.     }
  381.  
  382.     screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, bpp, flags);
  383.     if(!screen)
  384.     {
  385.         fprintf(stderr, "Failed to open screen!\n");
  386.         exit(-1);
  387.     }
  388.  
  389.     SDL_WM_SetCaption("Ballfield", "Ballfield");
  390.     if(flags & SDL_FULLSCREEN)
  391.         SDL_ShowCursor(0);
  392.  
  393.     balls = ballfield_init();
  394.     if(!balls)
  395.     {
  396.         fprintf(stderr, "Failed to create ballfield!\n");
  397.         exit(-1);
  398.     }
  399.  
  400.     /*
  401.      * Load and prepare balls...
  402.      */
  403.     balls->use_alpha = alpha;
  404.     if( ballfield_load_gfx(balls, "<rwsdlex5$dir>/blueball.png", 0)
  405.                 ||
  406.             ballfield_load_gfx(balls, "<rwsdlex5$dir>/redball.png", 1) )
  407.     {
  408.         fprintf(stderr, "Could not load balls!\n");
  409.         exit(-1);
  410.     }
  411.  
  412.     /*
  413.      * Load background image
  414.      */
  415.     temp_image = IMG_Load("<rwsdlex5$dir>/redbluestars.png");
  416.     if(!temp_image)
  417.     {
  418.         fprintf(stderr, "Could not load background!\n");
  419.         exit(-1);
  420.     }
  421.     back = SDL_DisplayFormat(temp_image);
  422.     SDL_FreeSurface(temp_image);
  423.  
  424.     /*
  425.      * Load logo
  426.      */
  427.     temp_image = SDL_LoadBMP("<rwsdlex5$dir>/logo.bmp");
  428.     if(!temp_image)
  429.     {
  430.         fprintf(stderr, "Could not load logo!\n");
  431.         exit(-1);
  432.     }
  433.     SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY|SDL_RLEACCEL,
  434.             SDL_MapRGB(temp_image->format, 255, 0, 255));
  435.     logo = SDL_DisplayFormat(temp_image);
  436.     SDL_FreeSurface(temp_image);
  437.  
  438.     /*
  439.      * Load font
  440.      */
  441.     temp_image = SDL_LoadBMP("<rwsdlex5$dir>/font7x10.bmp");
  442.     if(!temp_image)
  443.     {
  444.         fprintf(stderr, "Could not load font!\n");
  445.         exit(-1);
  446.     }
  447.     SDL_SetColorKey(temp_image, SDL_SRCCOLORKEY|SDL_RLEACCEL,
  448.             SDL_MapRGB(temp_image->format, 255, 0, 255));
  449.     font = SDL_DisplayFormat(temp_image);
  450.     SDL_FreeSurface(temp_image);
  451.  
  452.     last_avg_tick = last_tick = SDL_GetTicks();
  453.     while(1)
  454.     {
  455.         SDL_Rect r;
  456.         if(SDL_PollEvent(&event) > 0)
  457.         {
  458.             if(event.type == SDL_MOUSEBUTTONDOWN)
  459.                 break;
  460.  
  461.             if(event.type & (SDL_KEYUP | SDL_KEYDOWN))
  462.             {
  463.                 Uint8    *keys = SDL_GetKeyState(&i);
  464.                 if(keys[SDLK_ESCAPE])
  465.                     break;
  466.             }
  467.         }
  468.  
  469.         /* Timing */
  470.         tick = SDL_GetTicks();
  471.         dt = (tick - last_tick) * 0.001f;
  472.         last_tick = tick;
  473.  
  474.         /* Background image */
  475.         tiled_back(back, screen, x_offs>>11, y_offs>>11);
  476.  
  477.         /* Ballfield */
  478.         ballfield_render(balls, screen);
  479.  
  480.         /* Logo */
  481.         r.x = 2;
  482.         r.y = 2;
  483.         SDL_BlitSurface(logo, NULL, screen, &r);
  484.  
  485.         /* FPS counter */
  486.         if(tick > fps_start + 500)
  487.         {
  488.             fps = (float)fps_count * 1000.0 / (tick - fps_start);
  489.             fps_count = 0;
  490.             fps_start = tick;
  491.         }
  492.         print_num(screen, font, screen->w-37, screen->h-12, fps);
  493.         ++fps_count;
  494.  
  495.         SDL_Flip(screen);
  496.  
  497.         /* Animate */
  498.         x_speed = 500.0 * sin(t * 0.37);
  499.         y_speed = 500.0 * sin(t * 0.53);
  500.         z_speed = 400.0 * sin(t * 0.21);
  501.  
  502.         ballfield_move(balls, x_speed, y_speed, z_speed);
  503.         x_offs -= x_speed;
  504.         y_offs -= y_speed;
  505.  
  506.         t += dt;
  507.     }
  508.  
  509.     ballfield_free(balls);
  510.     SDL_FreeSurface(back);
  511.     SDL_FreeSurface(logo);
  512.     SDL_FreeSurface(font);
  513.     exit(0);
  514. }
  515.