示例#1
0
文件: wfile.c 项目: Skiles/aseprite
/* al_findfirst:
 *  Initiates a directory search.
 */
int al_findfirst(AL_CONST char *pattern, struct al_ffblk *info, int attrib)
{
   struct FF_DATA *ff_data;
   char tmp[1024];

   /* allocate ff_data structure */
   ff_data = _AL_MALLOC(sizeof(struct FF_DATA));

   if (!ff_data) {
      *allegro_errno = ENOMEM;
      return -1;
   }

   /* attach it to the info structure */
   info->ff_data = (void *) ff_data;

   /* Windows defines specific flags for NTFS permissions:
    *   FA_TEMPORARY            0x0100
    *   FA_SPARSE_FILE          0x0200 
    *   FA_REPARSE_POINT        0x0400
    *   FA_COMPRESSED           0x0800
    *   FA_OFFLINE              0x1000
    *   FA_NOT_CONTENT_INDEXED  0x2000
    *   FA_ENCRYPTED            0x4000
    * so we must set them in the mask by default; moreover,
    * in order to avoid problems with flags added in the
    * future, we simply set all bits past the first byte.
    */
   ff_data->attrib = attrib | 0xFFFFFF00;

   /* start the search */
   errno = *allegro_errno = 0;

   if (get_filename_encoding() != U_UNICODE) {
      ff_data->handle = _findfirst(uconvert(pattern, U_CURRENT, tmp,
                                            U_ASCII, sizeof(tmp)),
                                            &ff_data->data.a);

      if (ff_data->handle < 0) {
         *allegro_errno = errno;
         _AL_FREE(ff_data);
         info->ff_data = NULL;
         return -1;
      }

      if (ff_data->data.a.attrib & ~ff_data->attrib) {
         if (al_findnext(info) != 0) {
            al_findclose(info);
            return -1;
         }
         else
            return 0;
      }
   }
   else {
      ff_data->handle = _wfindfirst((wchar_t*)uconvert(pattern, U_CURRENT, tmp,
                                                       U_UNICODE, sizeof(tmp)),
                                                       &ff_data->data.w);

      if (ff_data->handle < 0) {
         *allegro_errno = errno;
         _AL_FREE(ff_data);
         info->ff_data = NULL;
         return -1;
      }

      if (ff_data->data.w.attrib & ~ff_data->attrib) {
         if (al_findnext(info) != 0) {
            al_findclose(info);
            return -1;
         }
         else
            return 0;
      }
   }

   fill_ffblk(info);
   return 0;
}
示例#2
0
文件: jpg.c 项目: sesc4mt/mvcdecoder
static void load_jpg_entry_helper(ALLEGRO_FILE *fp,
                                  struct load_jpg_entry_helper_data *data)
{
    struct jpeg_decompress_struct cinfo;
    struct my_err_mgr jerr;
    ALLEGRO_LOCKED_REGION *lock;
    int w, h, s;

    data->error = false;

    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit;
    if (setjmp(jerr.jmpenv) != 0) {
        /* Longjmp'd. */
        data->error = true;
        goto longjmp_error;
    }

    data->buffer = _AL_MALLOC(BUFFER_SIZE);
    if (!data->buffer) {
        data->error = true;
        goto error;
    }

    jpeg_create_decompress(&cinfo);
    jpeg_packfile_src(&cinfo, fp, data->buffer);
    jpeg_read_header(&cinfo, true);
    jpeg_start_decompress(&cinfo);

    w = cinfo.output_width;
    h = cinfo.output_height;
    s = cinfo.output_components;

    /* Only one and three components make sense in a JPG file. */
    if (s != 1 && s != 3) {
        data->error = true;
        goto error;
    }

    data->bmp = al_create_bitmap(w, h);
    if (!data->bmp) {
        data->error = true;
        goto error;
    }

    /* Allegro's pixel format is endian independent, so that in
     * ALLEGRO_PIXEL_FORMAT_RGB_888 the lower 8 bits always hold the Blue
     * component.  On a little endian system this is in byte 0.  On a big
     * endian system this is in byte 2.
     *
     * libjpeg expects byte 0 to hold the Red component, byte 1 to hold the
     * Green component, byte 2 to hold the Blue component.  Hence on little
     * endian systems we need the opposite format, ALLEGRO_PIXEL_FORMAT_BGR_888.
     */
#ifdef ALLEGRO_BIG_ENDIAN
    lock = al_lock_bitmap(data->bmp, ALLEGRO_PIXEL_FORMAT_RGB_888,
                          ALLEGRO_LOCK_WRITEONLY);
#else
    lock = al_lock_bitmap(data->bmp, ALLEGRO_PIXEL_FORMAT_BGR_888,
                          ALLEGRO_LOCK_WRITEONLY);
#endif
    al_set_target_bitmap(data->bmp);

    if (s == 3) {
        /* Colour. */
        int y;

        for (y = cinfo.output_scanline; y < h; y = cinfo.output_scanline) {
            unsigned char *out[1];
            out[0] = ((unsigned char *)lock->data) + y * lock->pitch;
            jpeg_read_scanlines(&cinfo, (void *)out, 1);
        }
    }
    else if (s == 1) {
        /* Greyscale. */
        unsigned char *in;
        unsigned char *out;
        int x, y;

        data->row = _AL_MALLOC(w);
        for (y = cinfo.output_scanline; y < h; y = cinfo.output_scanline) {
            jpeg_read_scanlines(&cinfo, (void *)&data->row, 1);
            in = data->row;
            out = ((unsigned char *)lock->data) + y * lock->pitch;
            for (x = 0; x < w; x++) {
                *out++ = *in;
                *out++ = *in;
                *out++ = *in;
                in++;
            }
        }
    }

error:
    jpeg_finish_decompress(&cinfo);

longjmp_error:
    jpeg_destroy_decompress(&cinfo);

    if (data->bmp) {
        if (al_is_bitmap_locked(data->bmp)) {
            al_unlock_bitmap(data->bmp);
        }
        if (data->error) {
            al_destroy_bitmap(data->bmp);
            data->bmp = NULL;
        }
    }

    _AL_FREE(data->buffer);
    _AL_FREE(data->row);
}
示例#3
0
/* _WinMain:
 *  Entry point for Windows GUI programs, hooked by a macro in alwin.h,
 *  which makes it look as if the application can still have a normal
 *  main() function.
 */
int _WinMain(void *_main, void *hInst, void *hPrev, char *Cmd, int nShow)
{
    int (*mainfunc) (int argc, char *argv[]) = (int (*)(int, char *[]))_main;
    char *argbuf;
    char *cmdline;
    char **argv;
    int argc;
    int argc_max;
    int i, q;

    /* can't use parameter because it doesn't include the executable name */
    cmdline = GetCommandLine();
    i = strlen(cmdline) + 1;
    argbuf = _AL_MALLOC(i);
    memcpy(argbuf, cmdline, i);

    argc = 0;
    argc_max = 64;
    argv = _AL_MALLOC(sizeof(char *) * argc_max);
    if (!argv) {
        _AL_FREE(argbuf);
        return 1;
    }

    i = 0;

    /* parse commandline into argc/argv format */
    while (argbuf[i]) {
        while ((argbuf[i]) && (uisspace(argbuf[i])))
            i++;

        if (argbuf[i]) {
            if ((argbuf[i] == '\'') || (argbuf[i] == '"')) {
                q = argbuf[i++];
                if (!argbuf[i])
                    break;
            }
            else
                q = 0;

            argv[argc++] = &argbuf[i];

            if (argc >= argc_max) {
                argc_max += 64;
                argv = _AL_REALLOC(argv, sizeof(char *) * argc_max);
                if (!argv) {
                    _AL_FREE(argbuf);
                    return 1;
                }
            }

            while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (!uisspace(argbuf[i]))))
                i++;

            if (argbuf[i]) {
                argbuf[i] = 0;
                i++;
            }
        }
    }

    argv[argc] = NULL;

    /* call the application entry point */
    i = mainfunc(argc, argv);

    _AL_FREE(argv);
    _AL_FREE(argbuf);

    return i;
}
示例#4
0
/* _get_win_midi_driver_list:
 *  System driver hook for listing the available MIDI drivers. This generates
 *  the device list at runtime, to match whatever Windows devices are 
 *  available.
 */
_DRIVER_INFO *_get_win_midi_driver_list(void)
{
   MIDI_DRIVER *driver;
   MIDIOUTCAPS caps;
   MIDIINCAPS  caps_in;
   int num_drivers, i;

   if (!driver_list) {
      num_drivers = midiOutGetNumDevs();

      /* include the MIDI mapper (id == -1) */
      if (num_drivers)
	 num_drivers++;

      driver_list = _create_driver_list();

      /* MidiOut drivers */
      for (i=0; i<num_drivers; i++) {
         driver = _AL_MALLOC(sizeof(MIDI_DRIVER));
         memcpy(driver, &_midi_none, sizeof(MIDI_DRIVER));

         if (i == 0)
            driver->id = MIDI_WIN32MAPPER;
         else
            driver->id = MIDI_WIN32(i-1);

         midiOutGetDevCaps(i-1, &caps, sizeof(caps));

	 driver->ascii_name = strdup(caps.szPname);

	 driver->detect = midi_win32_detect;
	 driver->init = midi_win32_init;
	 driver->exit = midi_win32_exit;
	 driver->set_mixer_volume = midi_win32_set_mixer_volume;
	 driver->get_mixer_volume = midi_win32_get_mixer_volume;
	 driver->raw_midi = midi_win32_raw_midi;

         _driver_list_append_driver(&driver_list, driver->id, driver, TRUE);
      }

      /* MidiIn drivers */
      num_drivers = midiInGetNumDevs();
      for (i=0; i<num_drivers; i++) {
	 driver = _AL_MALLOC(sizeof(MIDI_DRIVER));
	 memcpy(driver, &_midi_none, sizeof(MIDI_DRIVER));

	 driver->id = MIDI_WIN32_IN(i); /* added MIDI_WIN32_IN to alwin.h */

	 midiInGetDevCaps(i, &caps_in, sizeof(caps_in));

	 driver->ascii_name = strdup(caps_in.szPname);

	 driver->detect = midi_win32_in_detect;
	 driver->init = midi_win32_in_init;
	 driver->exit = midi_win32_in_exit;

	 _driver_list_append_driver(&driver_list, driver->id, driver, TRUE);
      }

      /* cross-platform DIGital MIDi driver */
      _driver_list_append_driver(&driver_list, MIDI_DIGMID, &midi_digmid, TRUE);
   }

   return driver_list;
}
示例#5
0
/* alsa_init:
 *  ALSA init routine.
 */
static int alsa_init(int input, int voices)
{
   int ret = 0;
   char tmp1[128], tmp2[128];
   int format = 0;
   unsigned int numfrags = 0;
   snd_pcm_uframes_t fragsize;

   if (input) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported"));
      return -1;
   }

   ALSA9_CHECK(snd_output_stdio_attach(&snd_output, stdout, 0));

   alsa_device = get_config_string(uconvert_ascii("sound", tmp1),
				   uconvert_ascii("alsa_device", tmp2),
				   alsa_device);

   alsa_mixer_device = get_config_string(uconvert_ascii("sound", tmp1),
				   uconvert_ascii("alsa_mixer_device", tmp2),
				   alsa_mixer_device);

   fragsize = get_config_int(uconvert_ascii("sound", tmp1),
			     uconvert_ascii("alsa_fragsize", tmp2), 0);

   numfrags = get_config_int(uconvert_ascii("sound", tmp1),
			     uconvert_ascii("alsa_numfrags", tmp2),
			     ALSA_DEFAULT_NUMFRAGS);

   ret = snd_pcm_open(&pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
   if (ret < 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not open card/pcm device"));
      return -1;
   }

   snd_mixer_open(&alsa_mixer, 0);

   if (alsa_mixer
       && snd_mixer_attach(alsa_mixer, alsa_mixer_device) >= 0
       && snd_mixer_selem_register (alsa_mixer, NULL, NULL) >= 0
       && snd_mixer_load(alsa_mixer) >= 0) {
      const char *alsa_mixer_elem_name = get_config_string(uconvert_ascii("sound", tmp1),
							   uconvert_ascii("alsa_mixer_elem", tmp2),
							   "PCM");

      alsa_mixer_elem = snd_mixer_first_elem(alsa_mixer);

      while (alsa_mixer_elem) {
	 const char *name = snd_mixer_selem_get_name(alsa_mixer_elem);

	 if (strcasecmp(name, alsa_mixer_elem_name) == 0) {
	    snd_mixer_selem_get_playback_volume_range(alsa_mixer_elem, &alsa_mixer_elem_min, &alsa_mixer_elem_max);
	    alsa_mixer_allegro_ratio = (double) (alsa_mixer_elem_max - alsa_mixer_elem_min) / (double) 255;
	    break;
	 }

	 alsa_mixer_elem = snd_mixer_elem_next(alsa_mixer_elem);
      }
   }

   /* Set format variables. */
   alsa_bits = (_sound_bits == 8) ? 8 : 16;
   alsa_stereo = (_sound_stereo) ? 1 : 0;
   alsa_rate = (_sound_freq > 0) ? _sound_freq : 44100;
   alsa_signed = 0;

   format = ((alsa_bits == 16) ? SND_PCM_FORMAT_U16_NE : SND_PCM_FORMAT_U8);

   switch (format) {

      case SND_PCM_FORMAT_U8:
	 alsa_bits = 8;
	 break;

      case SND_PCM_FORMAT_U16_NE:
	 if (sizeof(short) != 2) {
	    ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
	    goto Error;
	 }
	 break;

      default:
	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
	 goto Error;
   }

   alsa_sample_size = (alsa_bits / 8) * (alsa_stereo ? 2 : 1);

   if (fragsize == 0) {
      unsigned int size = alsa_rate * ALSA_DEFAULT_BUFFER_MS / 1000 / numfrags;
      fragsize = 1;
      while (fragsize < size)
	 fragsize <<= 1;
   }

   snd_pcm_hw_params_malloc(&hwparams);
   snd_pcm_sw_params_malloc(&swparams);

   ALSA9_CHECK(snd_pcm_hw_params_any(pcm_handle, hwparams));
   ALSA9_CHECK(snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED));
   ALSA9_CHECK(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format));
   ALSA9_CHECK(snd_pcm_hw_params_set_channels(pcm_handle, hwparams, alsa_stereo + 1));

   ALSA9_CHECK(snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &alsa_rate, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &fragsize, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &numfrags, NULL)); 

   ALSA9_CHECK(snd_pcm_hw_params(pcm_handle, hwparams));

   ALSA9_CHECK(snd_pcm_hw_params_get_period_size(hwparams, &alsa_bufsize, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_get_periods(hwparams, &alsa_fragments, NULL));

   TRACE (PREFIX_I "alsa_bufsize = %ld, alsa_fragments = %d\n", alsa_bufsize, alsa_fragments);

   ALSA9_CHECK(snd_pcm_sw_params_current(pcm_handle, swparams));
   ALSA9_CHECK(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, alsa_bufsize));
   ALSA9_CHECK(snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, fragsize));
   ALSA9_CHECK(snd_pcm_sw_params_set_xfer_align(pcm_handle, swparams, 1));
   ALSA9_CHECK(snd_pcm_sw_params(pcm_handle, swparams));

   /* Allocate mixing buffer. */
   alsa_bufdata = _AL_MALLOC_ATOMIC(alsa_bufsize * alsa_sample_size);
   if (!alsa_bufdata) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer"));
      goto Error;
   }

   /* Initialise mixer. */
   digi_alsa.voices = voices;

   if (_mixer_init(alsa_bufsize * (alsa_stereo ? 2 : 1), alsa_rate,
		   alsa_stereo, ((alsa_bits == 16) ? 1 : 0),
		   &digi_alsa.voices) != 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer"));
      goto Error;
   }

   snd_pcm_prepare(pcm_handle);
   pdc = snd_pcm_poll_descriptors_count (pcm_handle);
   if (pdc <= 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Invalid poll descriptors count"));
      goto Error;
   }

   ufds = _AL_MALLOC(sizeof(struct pollfd) * pdc);
   if (ufds == NULL) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory for poll descriptors"));
      goto Error;
   }
   ALSA9_CHECK(snd_pcm_poll_descriptors(pcm_handle, ufds, pdc));

   poll_next = 0;

   _mix_some_samples((uintptr_t) alsa_bufdata, 0, alsa_signed);

   /* Add audio interrupt. */
   _unix_bg_man->register_func(alsa_update);

   uszprintf(alsa_desc, sizeof(alsa_desc),
	     get_config_text
	     ("Alsa 0.9, Device '%s': %d bits, %s, %d bps, %s"),
	     alsa_device, alsa_bits,
	     uconvert_ascii((alsa_signed ? "signed" : "unsigned"), tmp1),
	     alsa_rate, uconvert_ascii((alsa_stereo ? "stereo" : "mono"), tmp2));

   digi_driver->desc = alsa_desc;
   return 0;

 Error:
   if (pcm_handle) {
      snd_pcm_close(pcm_handle);
      pcm_handle = NULL;
   }

   return -1;
}
示例#6
0
HWND _al_win_create_window(ALLEGRO_DISPLAY *display, int width, int height, int flags)
{
   HWND my_window;
   RECT win_size;
   DWORD style;
   DWORD ex_style;
   int pos_x, pos_y;
   bool center = false;
   ALLEGRO_MONITOR_INFO info;
   ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)display;
   WINDOWINFO wi;
   int bw, bh;

   wi.cbSize = sizeof(WINDOWINFO);

   if (!(flags & ALLEGRO_FULLSCREEN)) {
      if  (flags & ALLEGRO_RESIZABLE) {
         style = WS_OVERLAPPEDWINDOW;
         ex_style = WS_EX_APPWINDOW|WS_EX_OVERLAPPEDWINDOW;
      }
      else {
         style = WS_SYSMENU | WS_MINIMIZEBOX;
         ex_style = WS_EX_APPWINDOW;
      }
   }
   else {
      style = WS_POPUP;
      ex_style = WS_EX_APPWINDOW;
   }

   al_get_new_window_position(&pos_x, &pos_y);
   if (pos_x == INT_MAX) {
   	pos_x = pos_y = 0;
      if (!(flags & ALLEGRO_FULLSCREEN)) {
         center = true;
      }
   }

   if (center) {
      //int a = al_get_current_video_adapter();
      int a = win_display->adapter;

      if (a == -1) {
         ALLEGRO_SYSTEM *sys = al_get_system_driver();
         unsigned int num;
         bool *is_fullscreen;
         unsigned int i;
         unsigned int fullscreen_found = 0;
         num = al_get_num_video_adapters();
         is_fullscreen = _AL_MALLOC(sizeof(bool)*num);
         memset(is_fullscreen, 0, sizeof(bool)*num);
         for (i = 0; i < sys->displays._size; i++) {
            ALLEGRO_DISPLAY **dptr = _al_vector_ref(&sys->displays, i);
            ALLEGRO_DISPLAY *d = *dptr;
            if (d->flags & ALLEGRO_FULLSCREEN) {
               ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)d;
               is_fullscreen[win_display->adapter] = true;
               fullscreen_found++;
            }
         }
         if (fullscreen_found && fullscreen_found < num) {
            for (i = 0; i < num; i++) {
               if (is_fullscreen[i] == false) {
                  a = i;
                  break;
               }
            }
         }
         else
            a = 0;
         _AL_FREE(is_fullscreen);
      }

      al_set_current_video_adapter(a);

      al_get_monitor_info(a, &info);

      win_size.left = info.x1 + (info.x2 - info.x1 - width) / 2;
      win_size.right = win_size.left + width;
      win_size.top = info.y1 + (info.y2 - info.y1 - height) / 2;
      win_size.bottom = win_size.top + height;

      AdjustWindowRectEx(&win_size, style, false, ex_style);

      pos_x = win_size.left;
      pos_y = win_size.top;
   }

   my_window = CreateWindowEx(ex_style,
      "ALEX", "Allegro", style,
      pos_x, pos_y, width, height,
      NULL,NULL,window_class.hInstance,0);

   GetWindowInfo(my_window, &wi);
      
   bw = (wi.rcClient.left - wi.rcWindow.left) + (wi.rcWindow.right - wi.rcClient.right),
   bh = (wi.rcClient.top - wi.rcWindow.top) + (wi.rcWindow.bottom - wi.rcClient.bottom),

   SetWindowPos(my_window, 0, pos_x-bw/2, pos_y-bh/2,
      width+bw,
      height+bh,
      SWP_NOMOVE | SWP_NOZORDER);

   if (flags & ALLEGRO_NOFRAME) {
      SetWindowLong(my_window, GWL_STYLE, WS_VISIBLE);
      SetWindowLong(my_window, GWL_EXSTYLE, WS_EX_APPWINDOW);
      SetWindowPos(my_window, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
   }

   ShowWindow(my_window, SW_SHOW);

   if (!(flags & ALLEGRO_RESIZABLE) && !(flags & ALLEGRO_FULLSCREEN)) {
      /* Make the window non-resizable */
      HMENU menu;
      menu = GetSystemMenu(my_window, false);
      DeleteMenu(menu, SC_SIZE, MF_BYCOMMAND);
      DeleteMenu(menu, SC_MAXIMIZE, MF_BYCOMMAND);
      DrawMenuBar(my_window);
   }

   return my_window;
}
示例#7
0
/* create_video_bitmap:
 *  Attempts to make a bitmap object for accessing offscreen video memory.
 *
 *  The algorithm is similar to algorithms for drawing polygons. Think of
 *  a horizontal stripe whose height is equal to that of the new bitmap.
 *  It is initially aligned to the top of video memory and then it moves
 *  downwards, stopping each time its top coincides with the bottom of a
 *  video bitmap. For each stop, create a list of video bitmaps intersecting
 *  the stripe, sorted by the left coordinate, from left to right, in the
 *  next_x linked list. We look through this list and stop as soon as the
 *  gap between the rightmost right edge seen so far and the current left
 *  edge is big enough for the new video bitmap. In that case, we are done.
 *  If we don't find such a gap, we move the stripe further down.
 *
 *  To make it efficient to find new bitmaps intersecting the stripe, the
 *  list of all bitmaps is always sorted by top, from top to bottom, in
 *  the next_y linked list. The list of bitmaps intersecting the stripe is
 *  merely updated, not recalculated from scratch, when we move the stripe.
 *  So every bitmap gets bubbled to its correct sorted x-position at most
 *  once. Bubbling a bitmap takes at most as many steps as the number of
 *  video bitmaps. So the algorithm behaves at most quadratically with
 *  regard to the number of video bitmaps. I think that a linear behaviour
 *  is more typical in practical applications (this happens, for instance,
 *  if you allocate many bitmaps of the same height).
 *
 *  There's one more optimization: if a call fails, we cache the size of the
 *  requested bitmap, so that next time we can detect very quickly that this
 *  size is too large (this needs to be maintained when destroying bitmaps).
 */
BITMAP *create_video_bitmap(int width, int height)
{
   VRAM_BITMAP *active_list, *b, *vram_bitmap;
   VRAM_BITMAP **last_p;
   BITMAP *bmp;
   int x = 0, y = 0;

   ASSERT(width >= 0);
   ASSERT(height > 0);
   
   if (_dispsw_status)
      return NULL;

   /* let the driver handle the request if it can */
   if (gfx_driver->create_video_bitmap) {
      bmp = gfx_driver->create_video_bitmap(width, height);
      if (!bmp)
	 return NULL;

      b = _AL_MALLOC(sizeof(VRAM_BITMAP));
      b->x = -1;
      b->y = -1;
      b->w = 0;
      b->h = 0;
      b->bmp = bmp;
      b->next_y = vram_bitmap_list;
      vram_bitmap_list = b;

      return bmp;
   }

   /* check bad args */
   if ((width > VIRTUAL_W) || (height > VIRTUAL_H) ||
       (width < 0) || (height < 0))
      return NULL;

   /* check cached bitmap size */
   if ((width >= failed_bitmap_w) && (height >= failed_bitmap_h))
      return NULL;

   vram_bitmap = vram_bitmap_list;
   active_list = NULL;
   y = 0;

   while (TRUE) {
      /* Move the blocks from the VRAM_BITMAP_LIST that intersect the
       * stripe to the ACTIVE_LIST: look through the VRAM_BITMAP_LIST
       * following the next_y link, grow the ACTIVE_LIST following
       * the next_x link and sorting by x-position.
       * (this loop runs in amortized quadratic time)
       */
      while (vram_bitmap && (vram_bitmap->y < y+height)) {
	 /* find sorted x-position */
	 last_p = &active_list;
	 for (b = active_list; b && (vram_bitmap->x > b->x); b = b->next_x)
	    last_p = &b->next_x;

	 /* insert */
	 *last_p = vram_bitmap;
	 vram_bitmap->next_x = b;

	 /* next video bitmap */
	 vram_bitmap = vram_bitmap->next_y;
      }

      x = 0;

      /* Look for holes to put our bitmap in.
       * (this loop runs in quadratic time)
       */
      for (b = active_list; b; b = b->next_x) {
	 if (x+width <= b->x)  /* hole is big enough? */
	    return add_vram_block(x, y, width, height);

         /* Move search x-position to the right edge of the
          * skipped bitmap if we are not already past it.
          * And check there is enough room before continuing.
          */
	 if (x < b->x + b->w) {
	    x = (b->x + b->w + 15) & ~15;
	    if (x+width > VIRTUAL_W)
	       break;
	 }
      }

      /* If the whole ACTIVE_LIST was scanned, there is a big
       * enough hole to the right of the rightmost bitmap.
       */
      if (b == NULL)
	 return add_vram_block(x, y, width, height);

      /* Move search y-position to the topmost bottom edge
       * of the bitmaps intersecting the stripe.
       * (this loop runs in quadratic time)
       */
      y = active_list->y + active_list->h;
      for (b = active_list->next_x; b; b = b->next_x) {
	 if (y > b->y + b->h)
	    y = b->y + b->h;
      }

      if (y+height > VIRTUAL_H) {  /* too close to bottom? */
	 /* Before failing, cache this bitmap size so that later calls can
	  * learn from it. Use area as a measure to sort the bitmap sizes.
          */
	 if (width * height < failed_bitmap_w * failed_bitmap_h) {
	    failed_bitmap_w = width;
	    failed_bitmap_h = height;
	 }

	 return NULL;
      }

      /* Remove the blocks that don't intersect the new stripe from ACTIVE_LIST.
       * (this loop runs in quadratic time)
       */
      last_p = &active_list;
      for (b = active_list; b; b = b->next_x) {
	 if (y >= b->y + b->h)
	    *last_p = b->next_x;
	 else
	    last_p = &b->next_x;
      }
   }
}
示例#8
0
/* al_findfirst:
 *  Initiates a directory search.
 */
int al_findfirst(AL_CONST char *pattern, struct al_ffblk *info, int attrib)
{
   struct FF_DATA *ff_data;
   struct stat s;
   int actual_attrib;
   char tmp[1024];
   char *p;

   /* allocate ff_data structure */
   ff_data = _AL_MALLOC(sizeof(struct FF_DATA));
   if (!ff_data) {
      *allegro_errno = ENOMEM;
      return -1;
   }

   memset(ff_data, 0, sizeof *ff_data);
   info->ff_data = (void *) ff_data;

   /* if the pattern contains no wildcard, we use stat() */
   if (!ustrpbrk(pattern, uconvert("?*", U_ASCII, tmp, U_CURRENT, sizeof(tmp)))) {
      /* start the search */
      errno = *allegro_errno = 0;

      if (stat(uconvert(pattern, U_CURRENT, tmp, U_UTF8, sizeof(tmp)), &s) == 0) {
         /* get file attributes */
         actual_attrib = ff_get_attrib(ff_get_filename(uconvert(pattern, U_CURRENT, tmp, U_UTF8, sizeof(tmp))), &s);

         /* does it match ? */
         if ((actual_attrib & ~attrib) == 0) {
            info->attrib = actual_attrib;
            info->time = s.st_mtime;
            info->size = s.st_size; /* overflows at 2GB */
            ff_data->size = s.st_size;
            ustrzcpy(info->name, sizeof(info->name), get_filename(pattern));
            return 0;
         }
      }

       _AL_FREE(ff_data);
      info->ff_data = NULL;
      *allegro_errno = (errno ? errno : ENOENT);
      return -1;
   }

   ff_data->attrib = attrib;

   do_uconvert(pattern, U_CURRENT, ff_data->dirname, U_UTF8, sizeof(ff_data->dirname));
   p = ff_get_filename(ff_data->dirname);
   _al_sane_strncpy(ff_data->pattern, p, sizeof(ff_data->pattern));
   if (p == ff_data->dirname)
      _al_sane_strncpy(ff_data->dirname, "./", FF_MAXPATHLEN);
   else
      *p = 0;

   /* nasty bodge, but gives better compatibility with DOS programs */
   if (strcmp(ff_data->pattern, "*.*") == 0)
      _al_sane_strncpy(ff_data->pattern, "*", FF_MAXPATHLEN);

   /* start the search */
   errno = *allegro_errno = 0;

   ff_data->dir = opendir(ff_data->dirname);

   if (!ff_data->dir) {
      *allegro_errno = (errno ? errno : ENOENT);
      _AL_FREE(ff_data);
      info->ff_data = NULL;
      return -1;
   }

   if (al_findnext(info) != 0) {
      al_findclose(info);
      return -1;
   }

   return 0;
}
示例#9
0
/* create_bitmap_ex
 *  Creates a new memory bitmap in the specified color_depth
 */
BITMAP *create_bitmap_ex(int color_depth, int width, int height)
{
   GFX_VTABLE *vtable;
   BITMAP *bitmap;
   int nr_pointers;
   int padding;
   int i;

   ASSERT(width >= 0);
   ASSERT(height > 0);
   ASSERT(system_driver);

   if (system_driver->create_bitmap)
      return system_driver->create_bitmap(color_depth, width, height);

   vtable = _get_vtable(color_depth);
   if (!vtable)
      return NULL;

   /* We need at least two pointers when drawing, otherwise we get crashes with
    * Electric Fence.  We think some of the assembly code assumes a second line
    * pointer is always available.
    */
   nr_pointers = MAX(2, height);
   bitmap = _AL_MALLOC(sizeof(BITMAP) + (sizeof(char *) * nr_pointers));
   if (!bitmap)
      return NULL;

   /* This avoids a crash for assembler code accessing the last pixel, as it
    * read 4 bytes instead of 3.
    */
   padding = (color_depth == 24) ? 1 : 0;

   bitmap->dat = _AL_MALLOC_ATOMIC(width * height * BYTES_PER_PIXEL(color_depth) + padding);
   if (!bitmap->dat) {
      _AL_FREE(bitmap);
      return NULL;
   }

   bitmap->w = bitmap->cr = width;
   bitmap->h = bitmap->cb = height;
   bitmap->clip = TRUE;
   bitmap->cl = bitmap->ct = 0;
   bitmap->vtable = vtable;
   bitmap->write_bank = bitmap->read_bank = _stub_bank_switch;
   bitmap->id = 0;
   bitmap->extra = NULL;
   bitmap->x_ofs = 0;
   bitmap->y_ofs = 0;
   bitmap->seg = _default_ds();

   if (height > 0) {
      bitmap->line[0] = bitmap->dat;
      for (i=1; i<height; i++)
         bitmap->line[i] = bitmap->line[i-1] + width * BYTES_PER_PIXEL(color_depth);
   }

   if (system_driver->created_bitmap)
      system_driver->created_bitmap(bitmap);

   return bitmap;
}
示例#10
0
/* create_sub_bitmap:
 *  Creates a sub bitmap, ie. a bitmap sharing drawing memory with a
 *  pre-existing bitmap, but possibly with different clipping settings.
 *  Usually will be smaller, and positioned at some arbitrary point.
 *
 *  Mark Wodrich is the owner of the brain responsible this hugely useful 
 *  and beautiful function.
 */
BITMAP *create_sub_bitmap(BITMAP *parent, int x, int y, int width, int height)
{
   BITMAP *bitmap;
   int nr_pointers;
   int i;

   ASSERT(parent);
   ASSERT((x >= 0) && (y >= 0) && (x < parent->w) && (y < parent->h));
   ASSERT((width > 0) && (height > 0));
   ASSERT(system_driver);

   if (x+width > parent->w) 
      width = parent->w-x;

   if (y+height > parent->h) 
      height = parent->h-y;

   if (parent->vtable->create_sub_bitmap)
      return parent->vtable->create_sub_bitmap(parent, x, y, width, height);

   if (system_driver->create_sub_bitmap)
      return system_driver->create_sub_bitmap(parent, x, y, width, height);

   /* get memory for structure and line pointers */
   /* (see create_bitmap for the reason we need at least two) */
   nr_pointers = MAX(2, height);
   bitmap = _AL_MALLOC(sizeof(BITMAP) + (sizeof(char *) * nr_pointers));
   if (!bitmap)
      return NULL;

   acquire_bitmap(parent);

   bitmap->w = bitmap->cr = width;
   bitmap->h = bitmap->cb = height;
   bitmap->clip = TRUE;
   bitmap->cl = bitmap->ct = 0;
   bitmap->vtable = parent->vtable;
   bitmap->write_bank = parent->write_bank;
   bitmap->read_bank = parent->read_bank;
   bitmap->dat = NULL;
   bitmap->extra = NULL;
   bitmap->x_ofs = x + parent->x_ofs;
   bitmap->y_ofs = y + parent->y_ofs;
   bitmap->seg = parent->seg;

   /* All bitmaps are created with zero ID's. When a sub-bitmap is created,
    * a unique ID is needed to identify the relationship when blitting from
    * one to the other. This is obtained from the global variable
    * _sub_bitmap_id_count, which provides a sequence of integers (yes I
    * know it will wrap eventually, but not for a long time :-) If the
    * parent already has an ID the sub-bitmap adopts it, otherwise a new
    * ID is given to both the parent and the child.
    */
   if (!(parent->id & BMP_ID_MASK)) {
      parent->id |= _sub_bitmap_id_count;
      _sub_bitmap_id_count = (_sub_bitmap_id_count+1) & BMP_ID_MASK;
   }

   bitmap->id = parent->id | BMP_ID_SUB;
   bitmap->id &= ~BMP_ID_LOCKED;

   if (is_planar_bitmap(bitmap))
      x /= 4;

   x *= BYTES_PER_PIXEL(bitmap_color_depth(bitmap));

   /* setup line pointers: each line points to a line in the parent bitmap */
   for (i=0; i<height; i++)
      bitmap->line[i] = parent->line[y+i] + x;

   if (bitmap->vtable->set_clip)
      bitmap->vtable->set_clip(bitmap);

   if (parent->vtable->created_sub_bitmap)
      parent->vtable->created_sub_bitmap(bitmap, parent);

   if (system_driver->created_sub_bitmap)
      system_driver->created_sub_bitmap(bitmap, parent);

   if (parent->id & BMP_ID_VIDEO)
      _register_switch_bitmap(bitmap, parent);

   release_bitmap(parent);

   return bitmap;
}
示例#11
0
/* Function: al_grab_font_from_bitmap
 */
ALLEGRO_FONT *al_grab_font_from_bitmap(ALLEGRO_BITMAP *bmp,
   int ranges_n, int ranges[])
{
   ALLEGRO_FONT *f;
   ALLEGRO_FONT_COLOR_DATA *cf, *prev = NULL;
   ALLEGRO_STATE backup;
   int i;
   ALLEGRO_COLOR mask = al_get_pixel(bmp, 0, 0);
   ALLEGRO_BITMAP *glyphs = NULL, *unmasked = NULL;
   int import_x = 0, import_y = 0;
   ALLEGRO_LOCKED_REGION *lock = NULL;
   int w, h;

   ASSERT(bmp);
   
   w = al_get_bitmap_width(bmp);
   h = al_get_bitmap_height(bmp);

   f = _AL_MALLOC(sizeof *f);
   memset(f, 0, sizeof *f);
   f->vtable = al_font_vtable_color;
   
   al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS);
   al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
   al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA);
   unmasked = al_clone_bitmap(bmp);
   /* At least with OpenGL, texture pixels at the very border of
    * the glyph are sometimes partly sampled from the yellow mask
    * pixels. To work around this, we replace the mask with full
    * transparency.
    * And we best do it on a memory copy to avoid loading back a texture.
    */
   al_convert_mask_to_alpha(unmasked, mask);
   al_restore_state(&backup);   

   al_store_state(&backup, ALLEGRO_STATE_BITMAP | ALLEGRO_STATE_BLENDER);
   al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA);

   for (i = 0; i < ranges_n; i++) {
      int first = ranges[i * 2];
      int last = ranges[i * 2 + 1];
      int n = 1 + last - first;
      cf = _AL_MALLOC(sizeof(ALLEGRO_FONT_COLOR_DATA));
      memset(cf, 0, sizeof *cf);

      if (prev)
         prev->next = cf;
      else
         f->data = cf;
      
      cf->bitmaps = _AL_MALLOC(sizeof(ALLEGRO_BITMAP*) * n);

      if (!glyphs) {
         glyphs = al_clone_bitmap(unmasked);
         if (!glyphs)
            goto cleanup_and_fail_on_error;

         lock = al_lock_bitmap(bmp,
            ALLEGRO_PIXEL_FORMAT_RGBA_8888, ALLEGRO_LOCK_READONLY);
      }
      cf->glyphs = glyphs;

      if (import_bitmap_font_color(lock->data, lock->pitch, w, h,
         cf->bitmaps, cf->glyphs, n,
         &import_x, &import_y)) {
         goto cleanup_and_fail_on_error;
      }
      else {
         cf->begin = first;
         cf->end = last + 1;
         prev = cf;
      }
   }
   al_restore_state(&backup);
   
   cf = f->data;
   if (cf)
      f->height = al_get_bitmap_height(cf->bitmaps[0]);

   if (lock)
      al_unlock_bitmap(bmp);

   if (unmasked)
       al_destroy_bitmap(unmasked);

   return f;

cleanup_and_fail_on_error:

   if (lock)
      al_unlock_bitmap(bmp);
   al_restore_state(&backup);
   al_destroy_font(f);
   if (unmasked)
       al_destroy_bitmap(unmasked);
   return NULL;
}
示例#12
0
/* Create a new system object for the dummy X11 driver. */
static ALLEGRO_SYSTEM *xglx_initialize(int flags)
{
   Display *x11display;
   Display *gfxdisplay;
   ALLEGRO_SYSTEM_XGLX *s;

   (void)flags;

#ifdef DEBUG_X11
   _Xdebug = 1;
#endif

   XInitThreads();

   /* Get an X11 display handle. */
   x11display = XOpenDisplay(0);
   if (!x11display) {
      ALLEGRO_ERROR("XOpenDisplay failed.\n");
      return NULL;
   }

   /* Never ask. */
   gfxdisplay = XOpenDisplay(0);
   if (!gfxdisplay) {
      ALLEGRO_ERROR("XOpenDisplay failed.\n");
      XCloseDisplay(x11display);
      return NULL;
   }

   _al_unix_init_time();

   s = _AL_MALLOC(sizeof *s);
   memset(s, 0, sizeof *s);

   /* We need to put *some* atom into the ClientMessage we send for
    * faking mouse movements with al_set_mouse_xy - so lets ask X11
    * for one here.
    */
   s->AllegroAtom = XInternAtom(x11display, "AllegroAtom", False);

   _al_mutex_init_recursive(&s->lock);
   _al_cond_init(&s->resized);
   s->inhibit_screensaver = false;

   _al_vector_init(&s->system.displays, sizeof (ALLEGRO_DISPLAY_XGLX *));

   s->gfxdisplay = gfxdisplay;
   s->x11display = x11display;

   s->system.vt = xglx_vt;

   ALLEGRO_INFO("XGLX driver connected to X11 (%s %d).\n",
      ServerVendor(s->x11display), VendorRelease(s->x11display));
   ALLEGRO_INFO("X11 protocol version %d.%d.\n",
      ProtocolVersion(s->x11display), ProtocolRevision(s->x11display));

#ifdef ALLEGRO_XWINDOWS_WITH_XINERAMA
   _al_xsys_xinerama_init(s);
#endif

   _al_xglx_store_video_mode(s);
   
   _al_thread_create(&s->thread, xglx_background_thread, s);

   ALLEGRO_INFO("events thread spawned.\n");

   return &s->system;
}
示例#13
0
/* ljoy_get_joystick: [primary thread]
 *
 *  Returns the address of a ALLEGRO_JOYSTICK structure for the device
 *  number NUM.  The top-level joystick functions will not call this
 *  function if joystick number NUM was already gotten.  If the
 *  device cannot be opened, NULL is returned.
 */
static ALLEGRO_JOYSTICK *ljoy_get_joystick(int num)
{
   ALLEGRO_JOYSTICK_LINUX *joy;
   int fd;

   /* Try to open the device. */
   fd = try_open_joy_device(num);
   if (fd == -1)
      return NULL;

   /* Allocate a structure for the joystick. */
   joy = _AL_MALLOC(sizeof *joy);
   if (!joy) {
      close(fd);
      return NULL;
   }
   memset(joy, 0, sizeof *joy);

   /* Initialise the event source part of it. */
   _al_event_source_init(&joy->parent.es);

   /* Fill in the joystick information fields. */
   {
      /* char tmp[128], tmp1[128], tmp2[128]; */
      char num_axes;
      char num_buttons;
      int throttle;
      int s, a, b;

      ioctl(fd, JSIOCGAXES, &num_axes);
      ioctl(fd, JSIOCGBUTTONS, &num_buttons);

      if (num_axes > TOTAL_JOYSTICK_AXES)
         num_axes = TOTAL_JOYSTICK_AXES;

      if (num_buttons > _AL_MAX_JOYSTICK_BUTTONS)
         num_buttons = _AL_MAX_JOYSTICK_BUTTONS;

      /* XXX use configuration system when we get one */
      throttle = -1;
#if 0
      /* User is allowed to override our simple assumption of which
       * axis number (kernel) the throttle is located at. */
      snprintf(tmp, sizeof(tmp), "throttle_axis_%d", num);
      throttle = get_config_int("joystick", tmp, -1);
      if (throttle == -1) {
         throttle = get_config_int("joystick", 
                                   "throttle_axis", -1);
      }
#endif

      /* Each pair of axes is assumed to make up a stick unless it 
       * is the sole remaining axis, or has been user specified, in 
       * which case it is a throttle. */

      for (s = 0, a = 0;
           s < _AL_MAX_JOYSTICK_STICKS && a < num_axes;
           s++)
      {
         if ((a == throttle) || (a == num_axes-1)) {
            /* One axis throttle. */
            joy->parent.info.stick[s].flags = ALLEGRO_JOYFLAG_ANALOGUE;
            joy->parent.info.stick[s].num_axes = 1;
            joy->parent.info.stick[s].axis[0].name = "Throttle";
            char *name = joy->parent.info.stick[s].axis[0].name;
            joy->parent.info.stick[s].name = _AL_MALLOC_ATOMIC(strlen(name) + 1);
            strcpy(joy->parent.info.stick[s].name, name);
            joy->axis_mapping[a].stick = s;
            joy->axis_mapping[a].axis = 0;
            a++;
         }
         else {
            /* Two axis stick. */
            joy->parent.info.stick[s].flags = ALLEGRO_JOYFLAG_ANALOGUE;
            joy->parent.info.stick[s].num_axes = 2;
            joy->parent.info.stick[s].axis[0].name = "X";
            joy->parent.info.stick[s].axis[1].name = "Y";
            joy->parent.info.stick[s].name = _AL_MALLOC_ATOMIC (32);
            snprintf((char *)joy->parent.info.stick[s].name, 32, "Stick %d", s+1);
            joy->axis_mapping[a].stick = s;
            joy->axis_mapping[a].axis = 0;
            a++;
            joy->axis_mapping[a].stick = s;
            joy->axis_mapping[a].axis = 1;
            a++;
         }
      }

      joy->parent.info.num_sticks = s;

      /* Do the buttons. */

      for (b = 0; b < num_buttons; b++) {
         joy->parent.info.button[b].name = _AL_MALLOC_ATOMIC (32);
         snprintf((char *)joy->parent.info.button[b].name, 32, "B%d", b+1);
      }

      joy->parent.info.num_buttons = num_buttons;
   }

   joy->parent.num = num;

   joy->fd = fd;

   /* Register the joystick with the fdwatch subsystem.  */
   _al_unix_start_watching_fd(joy->fd, ljoy_process_new_data, joy);

   return (ALLEGRO_JOYSTICK *) joy;
}
示例#14
0
文件: jpg.c 项目: sesc4mt/mvcdecoder
static void save_jpg_entry_helper(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp,
                                  struct save_jpg_entry_helper_data *data)
{
    struct jpeg_compress_struct cinfo;
    struct my_err_mgr jerr;
    ALLEGRO_LOCKED_REGION *lock;

    data->error = false;

    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit;
    if (setjmp(jerr.jmpenv)) {
        /* Longjmp'd. */
        data->error = true;
        goto longjmp_error;
    }

    data->buffer = _AL_MALLOC(BUFFER_SIZE);
    if (!data->buffer) {
        data->error = true;
        goto error;
    }

    jpeg_create_compress(&cinfo);
    jpeg_packfile_dest(&cinfo, fp, data->buffer);

    cinfo.image_width = al_get_bitmap_width(bmp);
    cinfo.image_height = al_get_bitmap_height(bmp);
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);

    jpeg_start_compress(&cinfo, 1);

    /* See comment in load_jpg_entry_helper. */
#ifdef ALLEGRO_BIG_ENDIAN
    lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_RGB_888,
                          ALLEGRO_LOCK_READONLY);
#else
    lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_BGR_888,
                          ALLEGRO_LOCK_READONLY);
#endif
    al_set_target_bitmap(bmp);

    while (cinfo.next_scanline < cinfo.image_height) {
        unsigned char *row[1];
        row[0] = ((unsigned char *)lock->data)
                 + cinfo.next_scanline * lock->pitch;
        jpeg_write_scanlines(&cinfo, (void *)row, 1);
    }

error:
    jpeg_finish_compress(&cinfo);

longjmp_error:
    jpeg_destroy_compress(&cinfo);

    if (al_is_bitmap_locked(bmp)) {
        al_unlock_bitmap(bmp);
    }

    _AL_FREE(data->buffer);
}
示例#15
0
/* _make_bitmap:
 *  Helper function for creating the screen bitmap. Sets up a bitmap 
 *  structure for addressing video memory at addr, and fills the bank 
 *  switching table using bank size/granularity information from the 
 *  specified graphics driver.
 */
BITMAP *_make_bitmap(int w, int h, uintptr_t addr, GFX_DRIVER *driver, int color_depth, int bpl)
{
   GFX_VTABLE *vtable = _get_vtable(color_depth);
   int i, bank, size;
   BITMAP *b;

   if (!vtable)
      return NULL;

   size = sizeof(BITMAP) + sizeof(char *) * h;

   b = (BITMAP *)_AL_MALLOC(size);
   if (!b)
      return NULL;

   _gfx_bank = _AL_REALLOC(_gfx_bank, h * sizeof(int));
   if (!_gfx_bank) {
      _AL_FREE(b);
      return NULL;
   }

   LOCK_DATA(b, size);
   LOCK_DATA(_gfx_bank, h * sizeof(int));

   b->w = b->cr = w;
   b->h = b->cb = h;
   b->clip = TRUE;
   b->cl = b->ct = 0;
   b->vtable = &_screen_vtable;
   b->write_bank = b->read_bank = _stub_bank_switch;
   b->dat = NULL;
   b->id = BMP_ID_VIDEO;
   b->extra = NULL;
   b->x_ofs = 0;
   b->y_ofs = 0;
   b->seg = _video_ds();

   memcpy(&_screen_vtable, vtable, sizeof(GFX_VTABLE));
   LOCK_DATA(&_screen_vtable, sizeof(GFX_VTABLE));

   _last_bank_1 = _last_bank_2 = -1;

   driver->vid_phys_base = addr;

   b->line[0] = (unsigned char *)addr;
   _gfx_bank[0] = 0;

   if (driver->linear) {
      for (i=1; i<h; i++) {
	 b->line[i] = b->line[i-1] + bpl;
	 _gfx_bank[i] = 0;
      }
   }
   else {
      bank = 0;

      for (i=1; i<h; i++) {
	 b->line[i] = b->line[i-1] + bpl;
	 if (b->line[i]+bpl-1 >= (unsigned char *)addr + driver->bank_size) {
	    while (b->line[i] >= (unsigned char *)addr + driver->bank_gran) {
	       b->line[i] -= driver->bank_gran;
	       bank++;
	    }
	 }
	 _gfx_bank[i] = bank;
      }
   }

   return b;
}
示例#16
0
/* ff_match:
 *  Matches two strings ('*' matches any number of characters,
 *  '?' matches any character).
 */
static int ff_match(AL_CONST char *s1, AL_CONST char *s2)
{
   static unsigned int size = 0;
   static struct FF_MATCH_DATA *data = NULL;
   AL_CONST char *s1end;
   int index, c1, c2;

   /* handle NULL arguments */
   if ((!s1) && (!s2)) {
      if (data) {
         _AL_FREE(data);
         data = NULL;
      }

      return 0;
   }

   s1end = s1 + strlen(s1);

   /* allocate larger working area if necessary */
   if (data && (size < strlen(s2))) {
      _AL_FREE(data);
      data = NULL;
   }

   if (!data) {
      size = strlen(s2);
      data = _AL_MALLOC(sizeof(struct FF_MATCH_DATA) * size * 2 + 1);
      if (!data)
         return 0;
   }

   index = 0;
   data[0].s1 = s1;
   data[0].s2 = s2;
   data[0].type = FF_MATCH_TRY;

   while (index >= 0) {
      s1 = data[index].s1;
      s2 = data[index].s2;
      c1 = *s1;
      c2 = *s2;

      switch (data[index].type) {

      case FF_MATCH_TRY:
         if (c2 == 0) {
            /* pattern exhausted */
            if (c1 == 0)
               return 1;
            else
               index--;
         }
         else if (c1 == 0) {
            /* string exhausted */
            while (*s2 == '*')
               s2++;
            if (*s2 == 0)
               return 1;
            else
               index--;
         }
         else if (c2 == '*') {
            /* try to match the rest of pattern with empty string */
            data[index++].type = FF_MATCH_ANY;
            data[index].s1 = s1end;
            data[index].s2 = s2 + 1;
            data[index].type = FF_MATCH_TRY;
         }
         else if ((c2 == '?') || (c1 == c2)) {
            /* try to match the rest */
            data[index++].type = FF_MATCH_ONE;
            data[index].s1 = s1 + 1;
            data[index].s2 = s2 + 1;
            data[index].type = FF_MATCH_TRY;
         }
         else
            index--;
         break;

      case FF_MATCH_ONE:
         /* the rest of string did not match, try earlier */
         index--;
         break;

      case FF_MATCH_ANY:
         /* rest of string did not match, try add more chars to string tail */
         if (--data[index + 1].s1 >= s1) {
            data[index + 1].type = FF_MATCH_TRY;
            index++;
         }
         else
            index--;
         break;

      default:
         /* this is a bird? This is a plane? No it's a bug!!! */
         return 0;
      }
   }

   return 0;
}
示例#17
0
static LRESULT CALLBACK window_callback(HWND hWnd, UINT message, 
    WPARAM wParam, LPARAM lParam)
{
   ALLEGRO_DISPLAY *d = NULL;
   ALLEGRO_DISPLAY_WIN *win_display = NULL;
   WINDOWINFO wi;
   int w;
   int h;
   int x;
   int y;
   unsigned int i;
   ALLEGRO_EVENT_SOURCE *es = NULL;
   ALLEGRO_SYSTEM *system = al_get_system_driver();

   wi.cbSize = sizeof(WINDOWINFO);

   if (message == _al_win_msg_call_proc) {
      ((void (*)(void*))wParam) ((void*)lParam);
      return 0;
   }

   if (!system) {
      return DefWindowProc(hWnd,message,wParam,lParam); 
   }

   if (message == _al_win_msg_suicide && wParam) {
      win_display = (ALLEGRO_DISPLAY_WIN*)wParam;
      win_display->end_thread = true;
      DestroyWindow(hWnd);
      return 0;
   }

   for (i = 0; i < system->displays._size; i++) {
      ALLEGRO_DISPLAY **dptr = _al_vector_ref(&system->displays, i);
      d = *dptr;
      win_display = (void*)d;
      if (win_display->window == hWnd) {
         es = &d->es;
         break;
      }
   }

   if (i == system->displays._size)
      return DefWindowProc(hWnd,message,wParam,lParam); 

   if (message == _al_win_msg_suicide) {
      win_display->end_thread = true;
      DestroyWindow(hWnd);
      return 0;
   }

   switch (message) {
      case WM_INPUT: 
      {
          UINT dwSize;
          LPBYTE lpb;
          RAWINPUT* raw;

          /* We can't uninstall WM_INPUT mesages. */
          if (!al_is_mouse_installed())
             break;

          GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, 
                          sizeof(RAWINPUTHEADER));
          lpb = malloc(sizeof(BYTE)*dwSize);
          if (lpb == NULL) 
              break;

          GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
          raw = (RAWINPUT*)lpb;

          if (raw->header.dwType != RIM_TYPEMOUSE) {
             free(lpb); 
             break;
          }

       {
          RAWMOUSE *rm = &raw->data.mouse;
          int x = raw->data.mouse.lLastX;
          int y = raw->data.mouse.lLastY;
          bool abs = rm->usFlags & (MOUSE_MOVE_ABSOLUTE
                                 || MOUSE_VIRTUAL_DESKTOP);
          if (abs || x || y)
             _al_win_mouse_handle_move(x, y, abs, win_display);

          if (rm->usButtonFlags & RI_MOUSE_BUTTON_1_DOWN)
             _al_win_mouse_handle_button(1, true, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_1_UP)
             _al_win_mouse_handle_button(1, false, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_2_DOWN)
             _al_win_mouse_handle_button(2, true, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_2_UP)
             _al_win_mouse_handle_button(2, false, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_3_DOWN)
             _al_win_mouse_handle_button(3, true, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_3_UP)
             _al_win_mouse_handle_button(3, false, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_4_DOWN)
             _al_win_mouse_handle_button(4, true, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_4_UP)
             _al_win_mouse_handle_button(4, false, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_5_DOWN)
             _al_win_mouse_handle_button(5, true, x, y, abs, win_display);
          if (rm->usButtonFlags & RI_MOUSE_BUTTON_5_UP)
             _al_win_mouse_handle_button(5, false, x, y, abs, win_display);

          if (rm->usButtonFlags & RI_MOUSE_WHEEL) {
             SHORT z = (SHORT)rm->usButtonData;
             _al_win_mouse_handle_wheel(z / WHEEL_DELTA, false, win_display);
          }
       }

          free(lpb); 
          break;
      }
      case WM_LBUTTONDOWN:
      case WM_LBUTTONUP: {
         int mx = GET_X_LPARAM(lParam);
         int my = GET_Y_LPARAM(lParam);
         bool down = (message == WM_LBUTTONDOWN);
         _al_win_mouse_handle_button(1, down, mx, my, true, win_display);
         handle_mouse_capture(down, hWnd);
         break;
      }
      case WM_MBUTTONDOWN:
      case WM_MBUTTONUP: {
         int mx = GET_X_LPARAM(lParam);
         int my = GET_Y_LPARAM(lParam);
         bool down = (message == WM_MBUTTONDOWN);
         _al_win_mouse_handle_button(3, down, mx, my, true, win_display);
         handle_mouse_capture(down, hWnd);
         break;
      }
      case WM_RBUTTONDOWN:
      case WM_RBUTTONUP: {
         int mx = GET_X_LPARAM(lParam);
         int my = GET_Y_LPARAM(lParam);
         bool down = (message == WM_RBUTTONDOWN);
         _al_win_mouse_handle_button(2, down, mx, my, true, win_display);
         handle_mouse_capture(down, hWnd);
         break;
      }
      case WM_XBUTTONDOWN:
      case WM_XBUTTONUP: {
         int mx = GET_X_LPARAM(lParam);
         int my = GET_Y_LPARAM(lParam);
         int button = HIWORD(wParam);
         bool down = (message == WM_XBUTTONDOWN);
         if (button == XBUTTON1)
            _al_win_mouse_handle_button(4, down, mx, my, true, win_display);
         else if (button == XBUTTON2)
            _al_win_mouse_handle_button(5, down, mx, my, true, win_display);
         handle_mouse_capture(down, hWnd);
         return TRUE;
      }
      case WM_MOUSEWHEEL: {
         int d = GET_WHEEL_DELTA_WPARAM(wParam);
         _al_win_mouse_handle_wheel(d / WHEEL_DELTA, false, win_display);
         return TRUE;
      }
      case WM_MOUSEMOVE: {
         TRACKMOUSEEVENT tme;
         int mx = GET_X_LPARAM(lParam);
         int my = GET_Y_LPARAM(lParam);

         if (win_display->mouse_cursor_shown && we_hid_the_mouse) {
            we_hid_the_mouse = false;
            win_display->display.vt->hide_mouse_cursor((void*)win_display);
         }

         _al_win_mouse_handle_move(mx, my, true, win_display);
         if (mx >= 0 && my >= 0 && mx < d->w && my < d->h) {
            tme.cbSize = sizeof(tme);
            tme.dwFlags = TME_QUERY;
            if (TrackMouseEvent(&tme) && !tme.hwndTrack) {
               tme.dwFlags = TME_LEAVE;
               tme.hwndTrack = hWnd;
               tme.dwHoverTime = 0;
               TrackMouseEvent(&tme);
               _al_win_mouse_handle_enter(win_display);
            }
         }

         break;
      }
      case WM_MOUSELEAVE: {
          _al_win_mouse_handle_leave(win_display);
          break;
      }
      case WM_CAPTURECHANGED: if (al_is_mouse_installed()) {
         int i;
         ALLEGRO_MOUSE_STATE state;
         if (!lParam || (HWND)lParam == hWnd)
            break;
         al_get_mouse_state(&state);
         for (i = 1; i <= 5; i++) {
            if (al_mouse_button_down(&state, i))
               _al_win_mouse_handle_button(i, 0, 0, 0, true, win_display);
         }
         break;
      }
      case WM_NCMOUSEMOVE: {
         if (!win_display->mouse_cursor_shown) {
            we_hid_the_mouse = true;
            win_display->display.vt->show_mouse_cursor((void*)win_display);
         }
         break;
      }
      case WM_SYSKEYDOWN: {
         int vcode = wParam; 
         bool repeated  = (lParam >> 30) & 0x1;
         _al_win_kbd_handle_key_press(0, vcode, repeated, win_display);
         break;
      }
      case WM_KEYDOWN: {
         int vcode = wParam; 
         int scode = (lParam >> 16) & 0xff;
         bool repeated  = (lParam >> 30) & 0x1;
         /* We can't use TranslateMessage() because we don't know if it will
            produce a WM_CHAR or not. */
         _al_win_kbd_handle_key_press(scode, vcode, repeated, win_display);
         break;
      }
      case WM_SYSKEYUP:
      case WM_KEYUP: {
         int vcode = wParam;
         _al_win_kbd_handle_key_release(vcode, win_display);
         break;
      }
      case WM_SYSCOMMAND: {
         if (_al_win_disable_screensaver &&
               ((wParam & 0xfff0) == SC_MONITORPOWER || (wParam & 0xfff0) == SC_SCREENSAVE)) {
            return 0;
         }
         else if ((wParam & 0xfff0) == SC_KEYMENU) {
            /* Prevent Windows from intercepting the ALT key.
               (Disables opening menus via the ALT key.) */
            return 0;
         }
         break;
      }
      case WM_PAINT: {
         if ((win_display->display.flags & ALLEGRO_GENERATE_EXPOSE_EVENTS) &&
                  _al_event_source_needs_to_generate_event(es)) {
            RECT r;
            HRGN hrgn;
            GetWindowRect(win_display->window, &r);
            hrgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);
            if (GetUpdateRgn(win_display->window, hrgn, false) != ERROR) {
               PAINTSTRUCT ps;
               DWORD size;
               LPRGNDATA rgndata;
               int n;
               int i;
               RECT *rects;
               BeginPaint(win_display->window, &ps);
               size = GetRegionData(hrgn, 0, NULL);
               rgndata = _AL_MALLOC(size);
               GetRegionData(hrgn, size, rgndata);
               n = rgndata->rdh.nCount;
               rects = (RECT *)rgndata->Buffer;
               //GetWindowInfo(win_display->window, &wi);
               _al_event_source_lock(es);
               for (i = 0; i < n; i++) {
                  ALLEGRO_EVENT event;
                  event.display.type = ALLEGRO_EVENT_DISPLAY_EXPOSE;
                  event.display.timestamp = al_current_time();
                  event.display.x = rects[i].left;
                  event.display.y = rects[i].top;
                  event.display.width = rects[i].right - rects[i].left;
                  event.display.height = rects[i].bottom - rects[i].top;
                  _al_event_source_emit_event(es, &event);
               }
               _al_event_source_unlock(es);
               _AL_FREE(rgndata);
               EndPaint(win_display->window, &ps);
               DeleteObject(hrgn);
            }
            return 0;
         }
         break;
      }

      case WM_SETCURSOR:
         switch (LOWORD(lParam)) {
            case HTLEFT:
            case HTRIGHT:
               SetCursor(LoadCursor(NULL, IDC_SIZEWE));
               break;
            case HTBOTTOM:
            case HTTOP:
               SetCursor(LoadCursor(NULL, IDC_SIZENS));
               break;
            case HTBOTTOMLEFT:
            case HTTOPRIGHT:
               SetCursor(LoadCursor(NULL, IDC_SIZENESW));
               break;
            case HTBOTTOMRIGHT:
            case HTTOPLEFT:
               SetCursor(LoadCursor(NULL, IDC_SIZENWSE));
               break;
            default:
               if (win_display->mouse_cursor_shown) {
                  SetCursor(win_display->mouse_selected_hcursor);
               }
               else {
                  SetCursor(NULL);
               }
               break;
         }
         return 1;
      case WM_ACTIVATE:
         if (LOWORD(wParam) != WA_INACTIVE) {
            /* This SetWindowPos is for faux-fullscreen windows that lost focus
             * so they can get placed back on top
             */
             // FIXME: this doesn't seem to work
            //SetWindowPos(win_display->window, HWND_TOP, 0, 0, 0, 0,
            //   SWP_NOMOVE | SWP_NOSIZE);
            if (d->vt->switch_in)
            	  d->vt->switch_in(d);
            _al_event_source_lock(es);
            if (_al_event_source_needs_to_generate_event(es)) {
               ALLEGRO_EVENT event;
               event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN;
               event.display.timestamp = al_current_time();
               _al_event_source_emit_event(es, &event);
            }
            _al_event_source_unlock(es);
            _al_win_grab_input(win_display);
            return 0;
         }
         else {
            if (d->flags & ALLEGRO_FULLSCREEN) {
               d->vt->switch_out(d);
            }
            _al_event_source_lock(es);
            if (_al_event_source_needs_to_generate_event(es)) {
               ALLEGRO_EVENT event;
               event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT;
               event.display.timestamp = al_current_time();
               _al_event_source_emit_event(es, &event);
            }
            _al_event_source_unlock(es);
            return 0;
         }
         break;
      case WM_MENUCHAR :
         return (MNC_CLOSE << 16) | (wParam & 0xffff);
      case WM_CLOSE:
         _al_event_source_lock(es);
         if (_al_event_source_needs_to_generate_event(es)) {
            ALLEGRO_EVENT event;
            event.display.type = ALLEGRO_EVENT_DISPLAY_CLOSE;
            event.display.timestamp = al_current_time();
            _al_event_source_emit_event(es, &event);
         }
         _al_event_source_unlock(es);
         return 0;
      case WM_SIZE:
         if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED) {
            /*
             * Delay the resize event so we don't get bogged down with them
             */
            if (!resize_postponed) {
               resize_postponed = true;
               postpone_resize(win_display->window);
            }
         }
         return 0;
      case WM_USER+0:
         /* Generate a resize event if the size has changed. We cannot asynchronously
          * change the display size here yet, since the user will only know about a
          * changed size after receiving the resize event. Here we merely add the
          * event to the queue.
          */
         GetWindowInfo(win_display->window, &wi);
         x = wi.rcClient.left;
         y = wi.rcClient.top;
         w = wi.rcClient.right - wi.rcClient.left;
         h = wi.rcClient.bottom - wi.rcClient.top;
         if (d->w != w || d->h != h) {
            _al_event_source_lock(es);
            if (_al_event_source_needs_to_generate_event(es)) {
               ALLEGRO_EVENT event;
               event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE;
               event.display.timestamp = al_current_time();
               event.display.x = x;
               event.display.y = y;
               event.display.width = w;
               event.display.height = h;
               _al_event_source_emit_event(es, &event);
            }

            /* Generate an expose event. */
            if (_al_event_source_needs_to_generate_event(es)) {
               ALLEGRO_EVENT event;
               event.display.type = ALLEGRO_EVENT_DISPLAY_EXPOSE;
               event.display.timestamp = al_current_time();
               event.display.x = x;
               event.display.y = y;
               event.display.width = w;
               event.display.height = h;
               _al_event_source_emit_event(es, &event);
            }
            _al_event_source_unlock(es);
         }
         resize_postponed = false;
         win_display->can_acknowledge = true;
         return 0;
   } 

   return DefWindowProc(hWnd,message,wParam,lParam); 
}
示例#18
0
文件: ogg.c 项目: sesc4mt/mvcdecoder
/* Function: al_load_ogg_vorbis_audio_stream_f
 */
ALLEGRO_AUDIO_STREAM *al_load_ogg_vorbis_audio_stream_f(ALLEGRO_FILE* file,
	size_t buffer_count, unsigned int samples)
{
   const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */
   OggVorbis_File* vf;
   vorbis_info* vi;
   int channels;
   long rate;
   long total_samples;
   long total_size;
   AL_OV_DATA* extra;
   ALLEGRO_AUDIO_STREAM* stream;

   extra = _AL_MALLOC(sizeof(AL_OV_DATA));
   if (extra == NULL) {
      ALLEGRO_ERROR("Failed to allocate AL_OV_DATA struct.\n");
      return NULL;
   }
   
   if (file == NULL) {
      ALLEGRO_WARN("File failed to open\n");
      fprintf(stderr, "File failed to open\n");
      return NULL;
   }
   
   extra->file = file;
   
   vf = _AL_MALLOC(sizeof(OggVorbis_File));
   if (ov_open_callbacks(extra, vf, NULL, 0, callbacks) < 0) {
      ALLEGRO_WARN("ogg: Input does not appear to be an Ogg bitstream.\n");
      al_fclose(file);
      return NULL;
   }

   extra->vf = vf;

   vi = ov_info(vf, -1);
   channels = vi->channels;
   rate = vi->rate;
   total_samples = ov_pcm_total(vf,-1);
   total_size = total_samples * channels * word_size;

   extra->vi = vi;

   extra->bitstream = -1;

   ALLEGRO_DEBUG("channels %d\n", channels);
   ALLEGRO_DEBUG("word_size %d\n", word_size);
   ALLEGRO_DEBUG("rate %ld\n", rate);
   ALLEGRO_DEBUG("total_samples %ld\n", total_samples);
   ALLEGRO_DEBUG("total_size %ld\n", total_size);
	
   stream = al_create_audio_stream(buffer_count, samples, rate,
            _al_word_size_to_depth_conf(word_size),
            _al_count_to_channel_conf(channels));
   if (!stream) {
      free(vf);
      return NULL;
   }

   stream->extra = extra;

   extra->loop_start = 0.0;
   extra->loop_end = ogg_stream_get_length(stream);
   stream->feed_thread = al_create_thread(_al_kcm_feed_stream, stream);
   stream->quit_feed_thread = false;
   stream->feeder = ogg_stream_update;
   stream->rewind_feeder = ogg_stream_rewind;
   stream->seek_feeder = ogg_stream_seek;
   stream->get_feeder_position = ogg_stream_get_position;
   stream->get_feeder_length = ogg_stream_get_length;
   stream->set_feeder_loop = ogg_stream_set_loop;
   stream->unload_feeder = ogg_stream_close;
   al_start_thread(stream->feed_thread);
	
   return stream;
}
示例#19
0
文件: wddbmp.c 项目: Skiles/aseprite
/* gfx_directx_create_video_bitmap:
 */
BITMAP *gfx_directx_create_video_bitmap(int width, int height)
{
   DDRAW_SURFACE *surf;
   BITMAP *bmp;

   /* try to detect page flipping and triple buffering patterns */
   if ((width == gfx_directx_forefront_bitmap->w) && (height == gfx_directx_forefront_bitmap->h)) {

      switch (n_flipping_pages) {

         case 0:
            /* recycle the forefront surface as the first flipping page */
            flipping_page[0] = DDRAW_SURFACE_OF(gfx_directx_forefront_bitmap);
            bmp = gfx_directx_make_bitmap_from_surface(flipping_page[0], width, height, BMP_ID_VIDEO);
            if (bmp) {
               flipping_page[0]->parent_bmp = bmp;
               n_flipping_pages++;
               return bmp;
            }
            else {
               flipping_page[0] = NULL;
               return NULL;
            }

         case 1:
         case 2:
            /* try to attach an additional page to the flipping chain */
            flipping_page[n_flipping_pages] = _AL_MALLOC(sizeof(DDRAW_SURFACE));
            if (recreate_flipping_chain(n_flipping_pages+1) == 0) {
               bmp = gfx_directx_make_bitmap_from_surface(flipping_page[n_flipping_pages], width, height, BMP_ID_VIDEO);
               if (bmp) {
                  flipping_page[n_flipping_pages]->parent_bmp = bmp;
                  n_flipping_pages++;
                  return bmp;
               }
            }

            recreate_flipping_chain(n_flipping_pages);
            _AL_FREE(flipping_page[n_flipping_pages]);
            flipping_page[n_flipping_pages] = NULL;
            return NULL;
      }
   }

   /* create the DirectDraw surface */
   if (ddpixel_format)
      surf = gfx_directx_create_surface(width, height, ddpixel_format, DDRAW_SURFACE_SYSTEM);
   else
      surf = gfx_directx_create_surface(width, height, NULL, DDRAW_SURFACE_VIDEO);

   if (!surf)
      return NULL;

   /* create the bitmap that wraps up the surface */
   bmp = gfx_directx_make_bitmap_from_surface(surf, width, height, BMP_ID_VIDEO);
   if (!bmp) {
      gfx_directx_destroy_surface(surf);
      return NULL;
   }

   return bmp;
}