/* gfx_gdi_lock: */ static void gfx_gdi_lock(struct BITMAP *bmp) { /* to prevent the drawing threads and the rendering proc * from concurrently accessing the dirty lines array */ _enter_gfx_critical(); /* arrange for drawing requests to pause when we are in the background */ if (!_win_app_foreground) { /* stop timer */ remove_int(render_proc); _exit_gfx_critical(); if (GFX_CRITICAL_RELEASED) _win_thread_switch_out(); _enter_gfx_critical(); /* restart timer */ install_int(render_proc, RENDER_DELAY); } lock_nesting++; bmp->id |= BMP_ID_LOCKED; }
/* unregister_ddraw_surface: * Removes a surface from the linked list. */ void unregister_ddraw_surface(DDRAW_SURFACE *surf) { DDRAW_SURFACE *item; _enter_gfx_critical(); item = ddraw_surface_list; while (item) { if (item == surf) { /* surface found, unlink now */ if (item->next) item->next->prev = item->prev; if (item->prev) item->prev->next = item->next; if (ddraw_surface_list == item) ddraw_surface_list = item->next; item->next = NULL; item->prev = NULL; break; } item = item->next; } _exit_gfx_critical(); }
/* ddraw_do_stretch_blit: * Accelerated stretch_blit, stretch_sprite, stretch_masked_blit */ static void ddraw_do_stretch_blit(struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int dest_width, int dest_height, int masked) { RECT dest_rect, source_rect; DDCOLORKEY src_key; HRESULT hr; BITMAP *dest_parent; BITMAP *source_parent; dest_rect.left = dest_x + dest->x_ofs; dest_rect.top = dest_y + dest->y_ofs; dest_rect.right = dest_x + dest->x_ofs + dest_width; dest_rect.bottom = dest_y + dest->y_ofs + dest_height; source_rect.left = source_x + source->x_ofs; source_rect.top = source_y + source->y_ofs; source_rect.right = source_x + source->x_ofs + source_width; source_rect.bottom = source_y + source->y_ofs + source_height; src_key.dwColorSpaceLowValue = source->vtable->mask_color; src_key.dwColorSpaceHighValue = source->vtable->mask_color; if ( ( (masked && (gfx_capabilities & GFX_HW_VRAM_STRETCH_BLIT_MASKED)) || (!masked && (gfx_capabilities & GFX_HW_VRAM_STRETCH_BLIT)) ) && ( is_video_bitmap(source) || is_system_bitmap(source) ) ) { /* find parents */ dest_parent = dest; while (dest_parent->id & BMP_ID_SUB) dest_parent = (BITMAP *)dest_parent->extra; source_parent = source; while (source_parent->id & BMP_ID_SUB) source_parent = (BITMAP *)source_parent->extra; _enter_gfx_critical(); gfx_directx_release_lock(dest); gfx_directx_release_lock(source); IDirectDrawSurface2_SetColorKey(DDRAW_SURFACE_OF(source_parent)->id, DDCKEY_SRCBLT, &src_key); hr = IDirectDrawSurface2_Blt(DDRAW_SURFACE_OF(dest_parent)->id, &dest_rect, DDRAW_SURFACE_OF(source_parent)->id, &source_rect, (masked ? DDBLT_KEYSRC : 0) | DDBLT_WAIT, NULL); _exit_gfx_critical(); if (FAILED(hr)) _TRACE(PREFIX_E "Blt failed (%x)\n", hr); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (dest_parent == gfx_directx_forefront_bitmap)) win_gfx_driver->paint(&dest_rect); } else { /* have to use the original software version */ _orig_stretch_blit(source, dest, source_x, source_y, source_width, source_height, dest_x, dest_y, dest_width, dest_height, masked); } }
/* gfx_directx_switch_out: * Arranges for drawing requests to pause when we are in the background. */ static void gfx_directx_switch_out(void) { _exit_gfx_critical(); if (GFX_CRITICAL_RELEASED) _win_thread_switch_out(); _enter_gfx_critical(); }
/* restore_all_ddraw_surfaces: * Restores all the surfaces. Returns 0 on success or -1 on failure, * in which case restoring is stopped at the first failure. */ int restore_all_ddraw_surfaces(void) { DDRAW_SURFACE *item = ddraw_surface_list; _enter_gfx_critical(); while (item) { if (gfx_directx_restore_surface(item) != 0) { _exit_gfx_critical(); return -1; } item = item->next; } _exit_gfx_critical(); _TRACE(PREFIX_I "all DirectDraw surfaces restored\n"); return 0; }
/* gfx_gdi_unlock: */ static void gfx_gdi_unlock(struct BITMAP *bmp) { if (lock_nesting > 0) { lock_nesting--; if (!lock_nesting) bmp->id &= ~BMP_ID_LOCKED; _exit_gfx_critical(); } }
/* gfx_gdi_set_palette: */ static void gfx_gdi_set_palette(AL_CONST struct RGB *p, int from, int to, int vsync) { int c; for (c=from; c<=to; c++) palette[c] = p[c]; /* invalidate the whole screen */ _enter_gfx_critical(); gdi_dirty_lines[0] = gdi_dirty_lines[gfx_gdi.h-1] = 1; _exit_gfx_critical(); }
/* register_ddraw_surface: * Adds a surface to the linked list. */ void register_ddraw_surface(DDRAW_SURFACE *surf) { _enter_gfx_critical(); surf->next = ddraw_surface_list; surf->prev = NULL; if (ddraw_surface_list) ddraw_surface_list->prev = surf; ddraw_surface_list = surf; _exit_gfx_critical(); }
/* restore_all_ddraw_surfaces: * Restores all the surfaces. Returns 0 on success or -1 on failure, * in which case restoring is stopped at the first failure. */ int restore_all_ddraw_surfaces(void) { DDRAW_SURFACE *item = ddraw_surface_list; HRESULT hr; _enter_gfx_critical(); while (item) { hr = IDirectDrawSurface2_Restore(item->id); if (FAILED(hr)) { _exit_gfx_critical(); return -1; } item = item->next; } _exit_gfx_critical(); _TRACE(PREFIX_I "all DirectDraw surfaces restored\n"); return 0; }
/* gdi_update_window: * Updates the window. */ static void gdi_update_window(RECT *rect) { HDC hdc; HWND allegro_wnd = win_get_window(); _enter_gfx_critical(); if (!gdi_screen) { _exit_gfx_critical(); return; } hdc = GetDC(allegro_wnd); if (_color_depth == 8) set_palette_to_hdc(hdc, palette); blit_to_hdc(gdi_screen, hdc, rect->left, rect->top, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); ReleaseDC(allegro_wnd, hdc); _exit_gfx_critical(); }
/* gfx_directx_autolock: * Locks the surface and prepares the lines array of the bitmap. * This version is used directly by the bank switch functions, ie. * it handles the autolocking mode, rather than being called directly. */ void gfx_directx_autolock(BITMAP *bmp) { DDRAW_SURFACE *surf; BITMAP *parent; int pitch; unsigned char *data; int y; if (bmp->id & BMP_ID_SUB) { /* if it's a sub-bitmap, start by locking our parent */ parent = (BITMAP *)bmp->extra; gfx_directx_autolock(parent); bmp->id |= BMP_ID_LOCKED; if (parent->id & BMP_ID_AUTOLOCK) { bmp->id |= BMP_ID_AUTOLOCK; parent->id &= ~BMP_ID_AUTOLOCK; } /* update the line array if our parent has moved */ pitch = (long)parent->line[1] - (long)parent->line[0]; data = parent->line[0] + (bmp->y_ofs - parent->y_ofs) * pitch + (bmp->x_ofs - parent->x_ofs) * BYTES_PER_PIXEL(bitmap_color_depth(bmp)); if (data != bmp->line[0]) { for (y = 0; y < bmp->h; y++) { bmp->line[y] = data; data += pitch; } } } else { /* this is a real bitmap, so can be locked directly */ surf = DDRAW_SURFACE_OF(bmp); if (surf->lock_nesting) { /* re-locking after a hwaccel, so don't change nesting state */ gfx_directx_lock(bmp); surf->lock_nesting--; _exit_gfx_critical(); } else { /* locking for the first time */ gfx_directx_lock(bmp); bmp->id |= BMP_ID_AUTOLOCK; } } }
/* gfx_gdi_exit: */ static void gfx_gdi_exit(struct BITMAP *bmp) { _enter_critical(); _enter_gfx_critical(); if (bmp) { save_window_pos(); clear_bitmap(bmp); } /* stop timer */ remove_int(render_proc); CloseHandle(vsync_event); /* disconnect from the system driver */ win_gfx_driver = NULL; /* destroy dirty lines array */ _AL_FREE(gdi_dirty_lines); gdi_dirty_lines = NULL; /* destroy screen surface */ _AL_FREE(screen_surf); gdi_screen = NULL; /* destroy mouse bitmaps */ if (wgdi_mouse_sprite) { destroy_bitmap(wgdi_mouse_sprite); wgdi_mouse_sprite = NULL; destroy_bitmap(mouse_frontbuffer); mouse_frontbuffer = NULL; destroy_bitmap(mouse_backbuffer); mouse_backbuffer = NULL; } _exit_gfx_critical(); /* before restoring video mode, hide window */ set_display_switch_mode(SWITCH_PAUSE); system_driver->restore_console_state(); restore_window_style(); _exit_critical(); }
/* gfx_directx_unlock: * Unlocks the surface. */ void gfx_directx_unlock(BITMAP *bmp) { DDRAW_SURFACE *surf; BITMAP *parent; HRESULT hr; if (bmp->id & BMP_ID_SUB) { /* recurse when unlocking sub-bitmaps */ parent = (BITMAP *)bmp->extra; gfx_directx_unlock(parent); if (!(parent->id & BMP_ID_LOCKED)) bmp->id &= ~BMP_ID_LOCKED; } else { /* regular bitmaps can be unlocked directly */ surf = DDRAW_SURFACE_OF(bmp); if (surf->lock_nesting > 0) { surf->lock_nesting--; if ((!surf->lock_nesting) && (bmp->id & BMP_ID_LOCKED)) { if (!(surf->flags & DDRAW_SURFACE_LOST)) { /* only unlock if it doesn't use pseudo video memory */ hr = IDirectDrawSurface2_Unlock(surf->id, NULL); /* If the surface has been lost, try to restore all surfaces * and, on success, try again to unlock the surface. */ if (hr == DDERR_SURFACELOST) { if (restore_all_ddraw_surfaces() == 0) hr = IDirectDrawSurface2_Unlock(surf->id, NULL); } if (FAILED(hr)) _TRACE(PREFIX_E "Can't unlock surface (%x)\n", hr); } bmp->id &= ~BMP_ID_LOCKED; } /* release bitmap for other threads */ _exit_gfx_critical(); } } }
/* unregister_all_ddraw_surfaces: * Removes all surfaces from the linked list. */ void unregister_all_ddraw_surfaces(void) { DDRAW_SURFACE *item, *next_item; _enter_gfx_critical(); next_item = ddraw_surface_list; while (next_item) { item = next_item; next_item = next_item->next; item->next = NULL; item->prev = NULL; } ddraw_surface_list = NULL; _exit_gfx_critical(); }
/* ddraw_blit_to_self: * Accelerated vram -> vram blitting routine. */ static void ddraw_blit_to_self(BITMAP * source, BITMAP * dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height) { RECT src_rect; int dest_parent_x = dest_x + dest->x_ofs; int dest_parent_y = dest_y + dest->y_ofs; BITMAP *dest_parent; BITMAP *source_parent; src_rect.left = source_x + source->x_ofs; src_rect.top = source_y + source->y_ofs; src_rect.right = source_x + source->x_ofs + width; src_rect.bottom = source_y + source->y_ofs + height; /* find parents */ dest_parent = dest; while (dest_parent->id & BMP_ID_SUB) dest_parent = (BITMAP *)dest_parent->extra; source_parent = source; while (source_parent->id & BMP_ID_SUB) source_parent = (BITMAP *)source_parent->extra; _enter_gfx_critical(); gfx_directx_release_lock(dest); gfx_directx_release_lock(source); IDirectDrawSurface2_BltFast(DDRAW_SURFACE_OF(dest_parent)->id, dest_parent_x, dest_parent_y, DDRAW_SURFACE_OF(source_parent)->id, &src_rect, DDBLTFAST_WAIT); _exit_gfx_critical(); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (dest_parent == gfx_directx_forefront_bitmap)) { src_rect.left = dest_parent_x; src_rect.top = dest_parent_y; src_rect.right = dest_parent_x + width; src_rect.bottom = dest_parent_y + height; win_gfx_driver->paint(&src_rect); } }
/* ddraw_clear_to_color: * Accelerated screen clear routine. */ static void ddraw_clear_to_color(BITMAP * bitmap, int color) { RECT dest_rect; HRESULT hr; DDBLTFX blt_fx; BITMAP *parent; dest_rect.left = bitmap->cl + bitmap->x_ofs; dest_rect.top = bitmap->ct + bitmap->y_ofs; dest_rect.right = bitmap->x_ofs + bitmap->cr; dest_rect.bottom = bitmap->y_ofs + bitmap->cb; /* find parent */ parent = bitmap; while (parent->id & BMP_ID_SUB) parent = (BITMAP *)parent->extra; /* set fill color */ blt_fx.dwSize = sizeof(blt_fx); blt_fx.dwDDFX = 0; blt_fx.dwFillColor = color; _enter_gfx_critical(); gfx_directx_release_lock(bitmap); hr = IDirectDrawSurface2_Blt(DDRAW_SURFACE_OF(parent)->id, &dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blt_fx); _exit_gfx_critical(); if (FAILED(hr)) _TRACE(PREFIX_E "Blt failed (%x)\n", hr); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (parent == gfx_directx_forefront_bitmap)) win_gfx_driver->paint(&dest_rect); }
/* ddraw_vline: * Accelerated vline routine. */ static void ddraw_vline(BITMAP *bitmap, int x, int y1, int y2, int color) { RECT dest_rect; HRESULT hr; DDBLTFX blt_fx; BITMAP *parent; if (_drawing_mode != DRAW_MODE_SOLID) { _orig_vline(bitmap, x, y1, y2, color); return; } if (y1 > y2) { int tmp = y1; y1 = y2; y2 = tmp; } if (bitmap->clip) { if ((x < bitmap->cl) || (x >= bitmap->cr)) return; if (y1 < bitmap->ct) y1 = bitmap->ct; if (y2 >= bitmap->cb) y2 = bitmap->cb-1; if (y2 < y1) return; } dest_rect.top = y1 + bitmap->y_ofs; dest_rect.left = x + bitmap->x_ofs; dest_rect.bottom = y2 + bitmap->y_ofs + 1; dest_rect.right = x + bitmap->x_ofs + 1; /* find parent */ parent = bitmap; while (parent->id & BMP_ID_SUB) parent = (BITMAP *)parent->extra; /* set fill color */ blt_fx.dwSize = sizeof(blt_fx); blt_fx.dwDDFX = 0; blt_fx.dwFillColor = color; _enter_gfx_critical(); gfx_directx_release_lock(bitmap); hr = IDirectDrawSurface2_Blt(DDRAW_SURFACE_OF(parent)->id, &dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blt_fx); _exit_gfx_critical(); if (FAILED(hr)) _TRACE(PREFIX_E "Blt failed (%x)\n", hr); /* only for windowed mode */ if ((gfx_driver->id == GFX_DIRECTX_WIN) && (parent == gfx_directx_forefront_bitmap)) win_gfx_driver->paint(&dest_rect); }
/* render_proc: * Timer proc that updates the window. */ static void render_proc(void) { int top_line, bottom_line; HDC hdc = NULL; HWND allegro_wnd = win_get_window(); /* to prevent reentrant calls */ if (render_semaphore) return; render_semaphore = TRUE; /* to prevent the drawing threads and the rendering proc * from concurrently accessing the dirty lines array. */ _enter_gfx_critical(); if (!gdi_screen) { _exit_gfx_critical(); render_semaphore = FALSE; return; } /* pseudo dirty rectangles mechanism: * at most only one GDI call is performed for each frame, * a true dirty rectangles mechanism makes the demo game * unplayable in 640x480 on my system. */ /* find the first dirty line */ top_line = 0; while (!gdi_dirty_lines[top_line]) top_line++; if (top_line < gfx_gdi.h) { /* find the last dirty line */ bottom_line = gfx_gdi.h-1; while (!gdi_dirty_lines[bottom_line]) bottom_line--; hdc = GetDC(allegro_wnd); if (_color_depth == 8) set_palette_to_hdc(hdc, palette); blit_to_hdc(gdi_screen, hdc, 0, top_line, 0, top_line, gfx_gdi.w, bottom_line - top_line + 1); /* update mouse pointer if needed */ if (mouse_on) { if ((mouse_ypos+wgdi_mouse_sprite->h > top_line) && (mouse_ypos <= bottom_line)) { blit(gdi_screen, mouse_backbuffer, mouse_xpos, mouse_ypos, 0, 0, mouse_backbuffer->w, mouse_backbuffer->h); update_mouse_pointer(mouse_xpos, mouse_ypos, TRUE); } } /* clean up the dirty lines */ while (top_line <= bottom_line) gdi_dirty_lines[top_line++] = 0; ReleaseDC(allegro_wnd, hdc); } _exit_gfx_critical(); /* simulate vertical retrace */ PulseEvent(vsync_event); render_semaphore = FALSE; }