/* 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; }
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); }
/* _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; }
/* _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; }
/* 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; }
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; }
/* 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; } } }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
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); }
/* _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; }
/* 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; }
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); }
/* 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; }
/* 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; }