/* * Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved. * * $Id: DEVPIXMP.C 1.15 1997/02/24 12:21:30 STEVEW Exp $ * $Locker: $ * * Device pixelmap methods */ #include #include #include #include #include "drv.h" #include "pm.h" #include "host.h" #include "shortcut.h" #include "brassert.h" BR_RCS_ID("$Id: DEVPIXMP.C 1.15 1997/02/24 12:21:30 STEVEW Exp $"); /* * Default dispatch table for device pixelmap (defined at end of file) */ static struct br_device_pixelmap_dispatch devicePixelmapDispatch; /* * Device pixelmap info. template */ #define F(f) offsetof(struct br_device_pixelmap, f) static struct br_tv_template_entry devicePixelmapTemplateEntries[] = { {BRT_WIDTH_I32, 0, F(pm_width), BRTV_QUERY | BRTV_ALL, BRTV_CONV_I32_U16, }, {BRT_HEIGHT_I32, 0, F(pm_height), BRTV_QUERY | BRTV_ALL, BRTV_CONV_I32_U16, }, {BRT_PIXEL_TYPE_U8, 0, F(pm_type), BRTV_QUERY | BRTV_ALL, BRTV_CONV_I32_U8, }, // {BRT_PIXEL_CHANNELS_TL, 0, 0, BRTV_QUERY | BRTV_ALL, BRTV_CONV_CUSTOM, }, // {BRT_INDEXED_B, 0, F(indexed), BRTV_QUERY | BRTV_ALL, BRTV_CONV_COPY, }, {BRT_OUTPUT_FACILITY_O, 0, F(output_facility), BRTV_QUERY | BRTV_ALL, BRTV_CONV_COPY, }, {BRT_IDENTIFIER_CSTR, 0, F(pm_identifier), BRTV_QUERY | BRTV_ALL, BRTV_CONV_COPY, }, {BRT_CLUT_O, 0, F(clut), BRTV_QUERY | BRTV_ALL, BRTV_CONV_COPY, }, {BRT_WINDOW_HANDLE_H, 0, F(hwnd), BRTV_QUERY | BRTV_ALL, BRTV_CONV_COPY, }, {BRT_LPDIRECTDRAWSURFACE_P, 0, F(surface), BRTV_QUERY | BRTV_ALL, BRTV_CONV_COPY, }, }; #undef F /* * Structures used to translate tokens and values */ struct hwnd_tokens { HWND hwnd; }; #define F(f) offsetof(struct hwnd_tokens, f) static struct br_tv_template_entry hwndTemplateEntries[] = { {BRT(WINDOW_HANDLE_H), F(hwnd), BRTV_SET, BRTV_CONV_COPY, }, }; #undef F /* * Create a new device pixelmap */ br_device_pixelmap * DevicePixelmapDirectDrawAllocate(br_device *dev, br_output_facility *facility, br_token_value *tv) { int size; br_int_32 count, bpp; br_uint_32 width, height; br_device_pixelmap *self; struct hwnd_tokens ht; RECT rect; DWORD flags; LPDIRECTDRAW ddraw; DDSURFACEDESC ddsd = { sizeof(DDSURFACEDESC) }; PALETTEENTRY *entries; UASSERT(dev != NULL); UASSERT(facility != NULL); UASSERT(tv != NULL); // Create hwndTemplate, if necessary ... if( dev->templates.hwndTemplate == NULL) { dev->templates.hwndTemplate = BrTVTemplateAllocate( dev->res, hwndTemplateEntries, BR_ASIZE(hwndTemplateEntries)); } /* * Get window handle */ ht.hwnd = NULL; BrTokenValueSetMany(&ht, &count, NULL, tv, dev->templates.hwndTemplate ); if( ht.hwnd == NULL ) { BR_ERROR0("The DirectDraw driver requires a window handle\n"); return NULL; } /* * Determine pixelmap dimensions */ if(facility->fullscreen) { width = facility->width; height = facility->height; } else { GetClientRect(ht.hwnd, &rect); width = rect.right; height = rect.bottom; } /* * Increment output facility instance counter */ facility->num_instances++; /* * Allocate device pixelmap */ self = BrResAllocate( dev->res, sizeof(*self), BR_MEMORY_OBJECT ); /* * Fill members */ self->dispatch = &devicePixelmapDispatch; self->device = dev ; self->pm_identifier = "DirectDraw:Screen"; self->pm_map = NULL; self->pm_flags = BR_PMF_NO_ACCESS; self->pm_copy_function = BR_PMCOPY_NORMAL; self->pm_base_x = 0; self->pm_base_y = 0; self->pm_width = (br_uint_16) width; self->pm_height = (br_uint_16) height; self->pm_origin_x = 0; self->pm_origin_y = 0; self->pm_row_bytes = 0; self->pm_pixels = NULL; self->pm_type = (br_uint_8) facility->colour_type; self->pixel_bits = (br_uint_16) facility->colour_bits; self->fullscreen = facility->fullscreen; self->hwnd = ht.hwnd; self->bPrimary = BR_TRUE ; self->output_facility = facility; /* * Create a DirectDraw object */ if(dev->create(NULL, &ddraw, NULL) != DD_OK) { BR_ERROR0("DirectDrawCreate failed.\n"); return NULL ; } if (IDirectDraw_QueryInterface(ddraw, &IID_IDirectDraw2, &self->DD) != DD_OK) { IDirectDraw_Release(ddraw); BR_ERROR0("DirectDrawCreate failed.\n"); return NULL ; } IDirectDraw_Release(ddraw); /* * Set cooperative level */ if (self->fullscreen) flags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT | (facility->modex || facility->standard_vga? DDSCL_ALLOWMODEX: 0); else flags = DDSCL_NORMAL; if (IDirectDraw2_SetCooperativeLevel(self->DD, self->hwnd, flags) != DD_OK) { BrResFree(self); return NULL; } /* * Change display mode if fullscreen */ if(self->fullscreen) { bpp = self->pixel_bits; if (bpp == 15) bpp = 16; if (IDirectDraw2_SetDisplayMode(self->DD, width, height, bpp, 0, (facility->standard_vga? DDSDM_STANDARDVGAMODE: 0)) != DD_OK) { BrResFree(self); return NULL; } } /* * Create a primary surface */ ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; /* * For ModeX modes we also allocate a back buffer since we cannot access the front buffer * at all */ if (facility->modex) { ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP; ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT; ddsd.dwBackBufferCount = 1; } if (IDirectDraw2_CreateSurface(self->DD, &ddsd, &self->surface, NULL) != DD_OK) { BrResFree(self); return NULL; } /* * For ModeX, find the back buffer */ if (facility->modex) { DDSCAPS caps = { DDSCAPS_BACKBUFFER }; if (IDirectDrawSurface_GetAttachedSurface(self->surface, &caps, &self->offscreen) != DD_OK) { BrResFree(self); return NULL; } } /* * Just double check that the expected pixel format was returned */ #if 1 memset(&ddsd.ddpfPixelFormat, 0, sizeof(DDPIXELFORMAT)); ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); if (IDirectDrawSurface_GetPixelFormat(self->surface, &ddsd.ddpfPixelFormat) != DD_OK) { BrResFree(self); return NULL; } /* * Simple comparison code to match the simple enumeration code */ switch (facility->colour_type) { case BR_PMT_INDEX_8: if (!(ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)) { BrResFree(self); return NULL; } break; case BR_PMT_RGB_555: if (!(ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB) || (ddsd.ddpfPixelFormat.dwRGBBitCount != 16) || (ddsd.ddpfPixelFormat.dwRBitMask != 0x00007c00) || (ddsd.ddpfPixelFormat.dwGBitMask != 0x000003e0) || (ddsd.ddpfPixelFormat.dwBBitMask != 0x0000001f)) { BrResFree(self); return NULL; } break; case BR_PMT_RGB_565: if (!(ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB) || (ddsd.ddpfPixelFormat.dwRGBBitCount != 16) || (ddsd.ddpfPixelFormat.dwRBitMask != 0x0000f800) || (ddsd.ddpfPixelFormat.dwGBitMask != 0x000007e0) || (ddsd.ddpfPixelFormat.dwBBitMask != 0x0000001f)) { BrResFree(self); return NULL; } break; case BR_PMT_RGB_888: if (!(ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB) || (ddsd.ddpfPixelFormat.dwRGBBitCount != 24) || (ddsd.ddpfPixelFormat.dwRBitMask != 0x00ff0000) || (ddsd.ddpfPixelFormat.dwGBitMask != 0x0000ff00) || (ddsd.ddpfPixelFormat.dwBBitMask != 0x000000ff)) { BrResFree(self); return NULL; } default: BrResFree(self); return NULL; } #endif /* * Create and configure a clipper object if not fullscreen */ if(self->fullscreen == BR_FALSE) { IDirectDraw2_CreateClipper(self->DD, 0, &self->clipper, NULL); IDirectDrawClipper_SetHWnd(self->clipper, 0, self->hwnd); IDirectDrawSurface_SetClipper(self->surface, self->clipper); } /* * Attach a CLUT to indexed surfaces */ switch(self->pm_type) { case BR_PMT_INDEX_8: self->clut = DeviceClutDirectDrawAllocate(dev, self, "DirectDraw-CLUT"); size = self->clut->syspal_size; entries = (PALETTEENTRY *)BrMemAllocate(size * sizeof(PALETTEENTRY), BR_MEMORY_SCRATCH); GetPaletteEntries(self->clut->palette, 0, size, entries); IDirectDraw2_CreatePalette(self->DD, DDPCAPS_8BIT | (facility->fullscreen? DDPCAPS_ALLOW256: 0), entries, &self->palette, NULL); IDirectDrawSurface_SetPalette(self->surface, self->palette); BrMemFree(entries); break; } /* * Add object to its container */ ObjectContainerAddFront(facility, (br_object *)self); return self; } br_device * BR_CMETHOD_DECL(br_device_pixelmap_dd, device)(br_device_pixelmap *self) { return self->device; } /* * br_device_pixelmap_dd::resize */ static void BR_CMETHOD_DECL(br_device_pixelmap_dd, resize)\ (br_device_pixelmap *self, br_int_32 width, br_int_32 height) { br_uint_16 bpp ; DDSURFACEDESC ddsd ; // Ignore requests to resize to zero width / height if ( ( width == 0 ) || ( height == 0 ) ) return ; /* * Adjust pixelmap members */ self->pm_width = (br_uint_16) width; self->pm_height = (br_uint_16) height; // Change display mode if fullscreen if ( self->fullscreen == BR_TRUE ) { self->surface->lpVtbl->Release( self->surface ); if((bpp = self->pixel_bits) == 15) bpp = 16; IDirectDraw2_SetDisplayMode(self->DD, width, height, bpp, 0, 0); // Create a primary surface memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; IDirectDraw2_CreateSurface(self->DD, &ddsd, &self->surface, NULL); if ( self->pm_type == BR_PMT_INDEX_8 ) IDirectDrawSurface_SetPalette(self->surface, self->palette); } } /* * br_device_pixelmap_dd::free */ static void BR_CMETHOD_DECL(br_device_pixelmap_dd, free)\ (br_device_pixelmap *self) { UASSERT(self->output_facility != NULL); if (!self->sub_pixelmap) { if (self->surface != NULL) IDirectDrawSurface_Release(self->surface); /* * Release DirectDraw object and items attached to it */ if (self->DD != NULL) { IDirectDraw2_SetCooperativeLevel(self->DD, NULL, DDSCL_NORMAL); IDirectDraw2_Release(self->DD); } } /* * Remove object from its container */ ObjectContainerRemove(self->output_facility, (br_object *)self); /* * Decrement instance counter */ self->output_facility->num_instances--; /* * Free pixelmap structure */ BrResFreeNoCallback(self); } /* * Structures used to translate tokens and values */ struct match_tokens { br_token use; br_int_32 pixel_bits; br_int_32 width; br_int_32 height; br_uint_8 type ; }; #define F(f) offsetof(struct match_tokens, f) static struct br_tv_template_entry matchTemplateEntries[] = { {BRT_USE_T, 0, F(use), BRTV_SET, BRTV_CONV_COPY, }, {BRT_PIXEL_BITS_I32, 0, F(pixel_bits), BRTV_SET, BRTV_CONV_COPY, }, {BRT_WIDTH_I32, 0, F(width), BRTV_SET, BRTV_CONV_COPY, }, {BRT_HEIGHT_I32, 0, F(height), BRTV_SET, BRTV_CONV_COPY, }, {BRT_PIXEL_TYPE_U8, 0, F(type), BRTV_SET, BRTV_CONV_COPY, }, }; #undef F /* * br_device_pixelmap_dd::match */ static br_error BR_CMETHOD_DECL(br_device_pixelmap_dd, match)\ (br_device_pixelmap *self, br_device_pixelmap **newpm, br_token_value *tv) { br_int_32 count; struct match_tokens mt = {BRT_NONE, 0}; UASSERT(newpm != NULL); UASSERT(tv != NULL); // Create match template, if required ... if ( self->device->templates.matchTemplate == NULL ) { self->device->templates.matchTemplate = BrTVTemplateAllocate(self->device->res, matchTemplateEntries, BR_ASIZE(matchTemplateEntries)); } /* * Set default width and height */ mt.width = self->pm_width; mt.height = self->pm_height; mt.type = self->pm_type ; /* * Convert match tokens */ BrTokenValueSetMany(&mt, &count, NULL, tv, self->device->templates.matchTemplate ); /* * Switch on match type */ switch(mt.use) { case BRT_OFFSCREEN: /* * Create matching offscreen buffer */ return BufferDirectDrawAllocateOff(self, newpm, mt.width, mt.height, mt.type); case BRT_CLONE: case BRT_DEPTH: case BRT_HIDDEN: case BRT_HIDDEN_BUFFER: /* * None of these match types is allowed */ return BRE_FAIL; default: return BRE_FAIL; } return BRE_OK; } /* * br_device_pixelmap_dd::doubleBuffer */ static br_error BR_CMETHOD_DECL(br_device_pixelmap_dd, doubleBuffer)\ (br_device_pixelmap *self, br_device_pixelmap *src) { POINT pt; RECT srect, drect; br_error error; UASSERT(self != NULL); UASSERT(src != NULL); /* * Set the source and destination RECTs */ SetRect(&srect, 0, 0, src->pm_width, src->pm_height); SetRect(&drect, 0, 0, self->pm_width, self->pm_height); /* * Offset if not fullscreen */ if (self->fullscreen == BR_FALSE) { pt.x = pt.y = 0; ClientToScreen(self->hwnd, &pt); OffsetRect(&drect, pt.x, pt.y); } /* * Blit the pixels */ while (1) { switch (IDirectDrawSurface_Blt(self->output_facility->modex? self->offscreen: self->surface, &drect, src->surface, &srect, DDBLT_WAIT, NULL)) { case DD_OK: /* * For ModeX modes we blit to the offscreen buffer and flip */ if (self->output_facility->modex) if (IDirectDrawSurface_Flip(self->surface, self->offscreen, DDFLIP_WAIT) == DD_OK) return BRE_OK; else return BRE_FAIL; return BRE_OK; case DDERR_SURFACELOST: // Ed has pointed out a bug here : #if 0 if (IDirectDrawSurface_Restore(self->output_facility->modex? self->offscreen: self->surface) != DD_OK || IDirectDrawSurface_Restore(src->surface) != DD_OK) #else // Don't restore secondary attached surfaces; instead restore their parent if (IDirectDrawSurface_Restore(self->surface) != DD_OK || IDirectDrawSurface_Restore(src->surface) != DD_OK) return BRE_FAIL; #endif break; case DDERR_WASSTILLDRAWING: break; default: return BRE_FAIL; } } } br_token BR_CMETHOD_DECL(br_device_pixelmap_dd, type)\ (br_device_pixelmap *self) { return BRT_DEVICE_PIXELMAP; } br_boolean BR_CMETHOD_DECL(br_device_pixelmap_dd, isType)\ (br_device_pixelmap *self, br_token t) { return (t == BRT_DEVICE_PIXELMAP) || (t == BRT_OBJECT); } br_int_32 BR_CMETHOD_DECL(br_device_pixelmap_dd, space)\ (br_device_pixelmap *self) { return sizeof(br_device_pixelmap); } struct br_tv_template * BR_CMETHOD_DECL(br_device_pixelmap_dd, queryTemplate)(br_device_pixelmap *self) { if ( self->device->templates.devicePixelmapTemplate == NULL ) self->device->templates.devicePixelmapTemplate = BrTVTemplateAllocate( self->device->res, devicePixelmapTemplateEntries, BR_ASIZE(devicePixelmapTemplateEntries)); return self->device->templates.devicePixelmapTemplate ; } /* * br_device_pixelmap_dd::allocateSub */ br_error BR_CMETHOD_DECL(br_device_pixelmap_dd, allocateSub)\ (br_device_pixelmap *self, br_device_pixelmap **newpm, br_rectangle *rect) { /* * Method is not supported */ return BRE_FAIL; } /* * Default dispatch table for device pixelmap */ static struct br_device_pixelmap_dispatch devicePixelmapDispatch = { NULL, NULL, NULL, NULL, BR_CMETHOD_REF(br_device_pixelmap_dd, free), BR_CMETHOD_REF(br_object_dd, identifier), BR_CMETHOD_REF(br_device_pixelmap_dd, type), BR_CMETHOD_REF(br_device_pixelmap_dd, isType), BR_CMETHOD_REF(br_device_pixelmap_dd, device), BR_CMETHOD_REF(br_device_pixelmap_dd, space), BR_CMETHOD_REF(br_device_pixelmap_dd, queryTemplate), BR_CMETHOD_REF(br_object, query), BR_CMETHOD_REF(br_object, queryBuffer), BR_CMETHOD_REF(br_object, queryMany), BR_CMETHOD_REF(br_object, queryManySize), BR_CMETHOD_REF(br_object, queryAll), BR_CMETHOD_REF(br_object, queryAllSize), BR_CMETHOD_REF(br_device_pixelmap_mem, validSource), BR_CMETHOD_REF(br_device_pixelmap_dd, resize), BR_CMETHOD_REF(br_device_pixelmap_dd, match), BR_CMETHOD_REF(br_device_pixelmap_dd, allocateSub), BR_CMETHOD_REF(br_device_pixelmap_ddo, copy), BR_CMETHOD_REF(br_device_pixelmap_gen, copyTo), BR_CMETHOD_REF(br_device_pixelmap_gen, copyFrom), BR_CMETHOD_REF(br_device_pixelmap_ddo, fill), BR_CMETHOD_REF(br_device_pixelmap_dd, doubleBuffer), BR_CMETHOD_REF(br_device_pixelmap_gen, copyDirty), BR_CMETHOD_REF(br_device_pixelmap_gen, copyToDirty), BR_CMETHOD_REF(br_device_pixelmap_gen, copyFromDirty), BR_CMETHOD_REF(br_device_pixelmap_ddo, fillDirty), BR_CMETHOD_REF(br_device_pixelmap_gen, doubleBufferDirty), BR_CMETHOD_REF(br_device_pixelmap_gen, rectangle), BR_CMETHOD_REF(br_device_pixelmap_gen, rectangle2), BR_CMETHOD_REF(br_device_pixelmap_ddo, rectangleCopy), BR_CMETHOD_REF(br_device_pixelmap_ddo, rectangleCopyTo), BR_CMETHOD_REF(br_device_pixelmap_ddo, rectangleCopyFrom), BR_CMETHOD_REF(br_device_pixelmap_ddo, rectangleStretchCopy), BR_CMETHOD_REF(br_device_pixelmap_ddo, rectangleStretchCopyTo), BR_CMETHOD_REF(br_device_pixelmap_ddo, rectangleStretchCopyFrom), BR_CMETHOD_REF(br_device_pixelmap_ddo, rectangleFill), BR_CMETHOD_REF(br_device_pixelmap_ddo, pixelSet), BR_CMETHOD_REF(br_device_pixelmap_ddo, line), BR_CMETHOD_REF(br_device_pixelmap_ddo, copyBits), BR_CMETHOD_REF(br_device_pixelmap_gen, text), BR_CMETHOD_REF(br_device_pixelmap_gen, textBounds), BR_CMETHOD_REF(br_device_pixelmap_mem, rowSize), BR_CMETHOD_REF(br_device_pixelmap_mem, rowQuery), BR_CMETHOD_REF(br_device_pixelmap_mem, rowSet), BR_CMETHOD_REF(br_device_pixelmap_ddo, pixelQuery), BR_CMETHOD_REF(br_device_pixelmap_mem, pixelAddressQuery), BR_CMETHOD_REF(br_device_pixelmap_mem, pixelAddressSet), BR_CMETHOD_REF(br_device_pixelmap_mem, originSet), BR_CMETHOD_REF(br_device_pixelmap_ddo, flush), BR_CMETHOD_REF(br_device_pixelmap_mem, synchronise), BR_CMETHOD_REF(br_device_pixelmap_ddo, directLock), BR_CMETHOD_REF(br_device_pixelmap_ddo, directUnlock), };