convert line ends
[canaan.git] / prj / tech / libsrc / lgd3d / texture.c
blob18cf1c0d00f5c3e88529cbd7c1a2a5ea9a3b4061
1 // $Header: x:/prj/tech/libsrc/lgd3d/RCS/texture.c 1.45 1998/04/27 15:00:24 KEVIN Exp $
2 #define WIN32_LEAN_AND_MEAN
3 #include <windows.h>
4 #include <d3d.h>
6 #include <appagg.h>
7 #include <cbchain.h>
8 #include <dbg.h>
9 #include <dispapi.h>
10 #include <g2.h>
11 #include <lgassert.h>
12 #include <wdispapi.h>
13 #include <wdispcb.h>
15 #include <lgd3d.h>
16 #include <setup.h>
17 #include <tdrv.h>
18 #include <texture.h>
19 #include <tmgr.h>
21 #ifndef SHIP
22 static const char *hResErrorMsg = "%s:\nFacility %i, Error %i";
23 #endif
24 #define CheckHResult(hRes, msg) \
25 AssertMsg3(hRes==0, hResErrorMsg, msg, (hRes>>16)&0x7fff, hRes&0xffff)
27 #ifndef SHIP
28 #include <mprintf.h>
29 static BOOL spew;
30 #define mono_printf(x) \
31 do { \
32 if (spew) \
33 mprintf x ; \
34 } while (0)
35 #else
36 #define mono_printf(x)
37 #endif
39 #ifdef MONO_SPEW
40 #define put_mono(c) \
41 do { \
42 uchar *p_mono = (uchar *)0xb0086; \
43 *p_mono = c; \
44 } while (0)
45 #else
46 #define put_mono(c)
47 #endif
49 #define GBitMask15 0x3e0
50 #define GBitMask16 0x7e0
52 D3DMATERIALHANDLE MaterialHandle[LGD3D_MAX_TEXTURES];
53 D3DTEXTUREHANDLE TextureHandle[LGD3D_MAX_TEXTURES];
54 grs_bitmap *TdrvBitmap[LGD3D_MAX_TEXTURES];
56 #define PF_GENERIC 0
57 #define PF_RGB 1
58 #define PF_ALPHA 2
59 #define PF_MASK 3
60 #define PF_MAX 3
61 #define PF_TRANS 128
64 typedef struct d3d_cookie {
65 union {
66 struct {
67 uchar wlog, hlog;
68 uchar flags;
69 uchar palette;
71 ulong value;
73 } d3d_cookie;
75 static DDPIXELFORMAT AlphaTextureFormat;
76 static DDPIXELFORMAT RGBTextureFormat;
77 static DDPIXELFORMAT PalTextureFormat;
78 static LPDDPIXELFORMAT FormatList[PF_MAX];
79 static DWORD DeviceSurfaceCaps;
80 static BOOL texture_RGB = FALSE;
81 static BOOL prefer_RGB = FALSE;
82 static BOOL using_local = FALSE;
83 static BOOL local_available = FALSE;
84 static BOOL agp_available = FALSE;
86 static BOOL TextureListInited = FALSE;
87 static LPD3DITEXTURE Texture[LGD3D_MAX_TEXTURES];
88 static LPDIRECTDRAWSURFACE Surface[LGD3D_MAX_TEXTURES];
90 static LPD3DIMATERIAL Material[LGD3D_MAX_TEXTURES];
92 #define MAX_PALETTES 256
94 static grs_bitmap *default_bm = NULL;
95 static LPDIRECTDRAWPALETTE lpDDPalTexture[MAX_PALETTES];
96 static LPDIRECTDRAW lpdd=NULL;
97 static LPDIRECTDRAW2 lpdd2=NULL;
98 static IWinDisplayDevice * pWinDisplayDevice = NULL;
100 static void CheckSurfaces(sWinDispDevCallbackInfo *data);
101 static int callback_id = 0;
103 static ushort default_alpha_pal[256];
104 static ushort *texture_pal[MAX_PALETTES];
105 static ushort *alpha_pal = NULL;
106 static uchar *texture_clut=NULL;
107 static DevDesc *device_desc;
108 static DWORD texture_caps;
110 void ShutdownTextureSys(void)
112 int i;
114 if (TextureListInited) {
115 if (g_tmgr!=NULL) {
116 g_tmgr->shutdown();
117 g_tmgr = NULL;
120 pWinDisplayDevice->lpVtbl->RemoveTaskSwitchCallback(
121 pWinDisplayDevice, callback_id);
123 // this is actually redundant since tmgr should take
124 // care of it, but it can't really hurt...
125 for (i=0; i<LGD3D_MAX_TEXTURES; i++) {
126 SafeRelease(Material[i]);
127 SafeRelease(Texture[i]);
128 SafeRelease(Surface[i]);
129 MaterialHandle[i]=0;
130 TextureHandle[i]=0;
132 TextureListInited = FALSE;
134 if (default_bm != NULL) {
135 gr_free(default_bm);
136 default_bm = NULL;
138 for (i=0; i<MAX_PALETTES; i++)
140 if (texture_pal[i]!=NULL) {
141 gr_free(texture_pal[i]);
142 texture_pal[i] = NULL;
144 SafeRelease(lpDDPalTexture[i]);
146 SafeRelease(lpdd2);
147 SafeRelease(lpdd);
148 SafeRelease(pWinDisplayDevice);
151 void lgd3d_set_texture_clut(uchar *clut)
153 texture_clut = clut;
154 if (g_tmgr!=NULL)
155 g_tmgr->set_clut(clut);
158 void lgd3d_set_alpha_pal(ushort *pal)
160 alpha_pal = pal;
163 void lgd3d_texture_set_RGB(bool is_RGB)
165 prefer_RGB = is_RGB;
168 void lgd3d_get_texture_bitmask(grs_rgb_bitmask *bitmask)
170 if (RGBTextureFormat.dwFlags == 0)
171 RGBTextureFormat.dwRBitMask =
172 RGBTextureFormat.dwGBitMask =
173 RGBTextureFormat.dwBBitMask = 0;
175 bitmask->red = RGBTextureFormat.dwRBitMask;
176 bitmask->green = RGBTextureFormat.dwGBitMask;
177 bitmask->blue = RGBTextureFormat.dwBBitMask;
181 static HRESULT InitMaterial(int tex_id)
183 D3DMATERIAL d3dMaterial;
184 HRESULT hRes;
185 LPD3DIMATERIAL Mat;
187 AssertMsg((tex_id>=0)&&(tex_id<LGD3D_MAX_TEXTURES), "Texture id out of range");
189 hRes = lpd3d->lpVtbl->CreateMaterial(
190 lpd3d,
191 &Mat,
192 NULL);
194 if (FAILED(hRes))
195 return hRes;
197 Material[tex_id] = Mat;
199 ZeroMemory(&d3dMaterial, sizeof(d3dMaterial));
200 d3dMaterial.dwSize = sizeof(d3dMaterial);
202 d3dMaterial.diffuse.r = D3DVAL(1.0);
203 d3dMaterial.diffuse.g = D3DVAL(1.0);
204 d3dMaterial.diffuse.b = D3DVAL(1.0);
205 d3dMaterial.ambient.r = D3DVAL(1.0);
206 d3dMaterial.ambient.g = D3DVAL(1.0);
207 d3dMaterial.ambient.b = D3DVAL(1.0);
208 d3dMaterial.specular.r = D3DVAL(0.0);
209 d3dMaterial.specular.g = D3DVAL(0.0);
210 d3dMaterial.specular.b = D3DVAL(0.0);
211 d3dMaterial.dvPower = D3DVAL(0.0);
212 d3dMaterial.hTexture = TextureHandle[tex_id];
213 d3dMaterial.dwRampSize = 1UL;
215 hRes = Mat->lpVtbl->SetMaterial(Mat, &d3dMaterial);
216 if (FAILED(hRes))
217 return hRes;
219 hRes = Mat->lpVtbl->GetHandle(Mat,
220 lpd3dDevice,
221 &MaterialHandle[tex_id]);
223 if (FAILED(hRes))
224 return hRes;
226 return DD_OK;
230 static HRESULT CALLBACK EnumTextureFormatsCallback(LPDDSURFACEDESC lpDDSD, LPVOID lpContext)
232 DDPIXELFORMAT *fmt = &lpDDSD->ddpfPixelFormat;
234 #ifdef SPEW_FORMATS
235 if (fmt->dwFlags&DDPF_RGB) {
236 mono_printf(("RGB bits: %i, alpha bits: %i\n", fmt->dwRGBBitCount, fmt->dwAlphaBitDepth));
237 mono_printf(("bitmasks: A %x, R %x G %x B %x\n",
238 fmt->dwRGBAlphaBitMask, fmt->dwRBitMask, fmt->dwGBitMask, fmt->dwBBitMask));
240 #endif
242 // Grab 4444 alpha format...
243 if ((fmt->dwFlags&DDPF_RGB)&&(fmt->dwRGBBitCount==16)&&
244 (fmt->dwRGBAlphaBitMask == 0xf000)&&
245 (fmt->dwRBitMask == 0xf00)&&
246 (fmt->dwGBitMask == 0xf0)&&
247 (fmt->dwBBitMask == 0xf)) {
248 memcpy(&AlphaTextureFormat, fmt, sizeof(AlphaTextureFormat));
250 // Grab 16 bit no alpha format...
251 else if ((fmt->dwFlags == DDPF_RGB)&&
252 (fmt->dwRGBBitCount == 16))
254 if ((fmt->dwGBitMask == GBitMask16) ||
255 (fmt->dwGBitMask == GBitMask15)) {
256 memcpy(&RGBTextureFormat, fmt, sizeof(RGBTextureFormat));
259 // Grab 8 bit palettized format
260 else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
261 memcpy(&PalTextureFormat, &lpDDSD->ddpfPixelFormat, sizeof(PalTextureFormat));
264 return DDENUMRET_OK;
267 #define NONLOCAL_CAPS DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_ALLOCONLOAD
268 #define LOCAL_CAPS DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_ALLOCONLOAD
270 static void EnumTextureFormats(void)
272 HRESULT hRes;
273 D3DDEVICEDESC hal, hel;
274 LPDIRECTDRAWSURFACE test_surf;
275 DDSURFACEDESC ddsd;
278 ZeroMemory(&RGBTextureFormat, sizeof(RGBTextureFormat));
279 ZeroMemory(&PalTextureFormat, sizeof(PalTextureFormat));
281 hRes = lpd3dDevice->lpVtbl->EnumTextureFormats(lpd3dDevice, EnumTextureFormatsCallback, NULL);
282 CheckHResult(hRes, "EnumTextureFormats failed");
284 texture_RGB = prefer_RGB;
285 FormatList[PF_GENERIC] = texture_RGB ? &RGBTextureFormat : &PalTextureFormat;
286 if (FormatList[PF_GENERIC]->dwFlags == 0) {
287 texture_RGB = !texture_RGB;
288 FormatList[PF_GENERIC] = texture_RGB ? &RGBTextureFormat : &PalTextureFormat;
289 if (FormatList[PF_GENERIC]->dwFlags == 0)
290 CriticalMsg("Direct3D device does not support 8 bit palettized or 15 or 16 bit RGB textures");
293 FormatList[PF_RGB] = &RGBTextureFormat;
294 FormatList[PF_ALPHA] = &AlphaTextureFormat;
296 mono_printf(("Using %s textures\n",texture_RGB ? "16 bit RGB" : "Palettized"));
298 if (AlphaTextureFormat.dwFlags == 0)
299 mono_printf(("no alpha texture format available.\n"));
302 ZeroMemory(&hal, sizeof(hal));
303 hal.dwSize = sizeof(hal);
304 ZeroMemory(&hel, sizeof(hel));
305 hel.dwSize = sizeof(hel);
307 hRes = lpd3dDevice->lpVtbl->GetCaps(lpd3dDevice, &hal, &hel);
308 CheckHResult(hRes, "Failed to obtain device caps");
310 AssertMsg(hal.dwFlags & D3DDD_DEVCAPS, "No HAL device!");
312 ZeroMemory(&ddsd, sizeof(ddsd));
313 memcpy(&ddsd.ddpfPixelFormat, FormatList[PF_GENERIC], sizeof(ddsd.ddpfPixelFormat));
314 ddsd.dwHeight = 256;
315 ddsd.dwWidth = 256;
316 agp_available = FALSE;
317 local_available = FALSE;
319 if (hal.dwDevCaps & D3DDEVCAPS_TEXTURENONLOCALVIDMEM) {
320 ddsd.dwSize = sizeof(DDSURFACEDESC);
321 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
322 ddsd.ddsCaps.dwCaps = NONLOCAL_CAPS;
323 hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &test_surf, NULL);
324 if ((hRes == DD_OK) && (test_surf != NULL)) {
325 SafeRelease(test_surf);
326 agp_available = TRUE;
327 DeviceSurfaceCaps = NONLOCAL_CAPS;
328 mono_printf(("nonlocal videomemory textures available.\n"));
332 if (hal.dwDevCaps & D3DDEVCAPS_TEXTUREVIDEOMEMORY) {
333 ddsd.dwSize = sizeof(DDSURFACEDESC);
334 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
335 ddsd.ddsCaps.dwCaps = LOCAL_CAPS;
336 hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &test_surf, NULL);
337 if ((hRes == DD_OK) && (test_surf != NULL)) {
338 SafeRelease(test_surf);
339 local_available = TRUE;
340 DeviceSurfaceCaps = LOCAL_CAPS;
341 mono_printf(("local videomemory textures available.\n"));
345 if (!(agp_available||local_available)) {
346 mono_printf(("No local or nonlocal texture memory! Using system memory textures.\n"));
347 DeviceSurfaceCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY | DDSCAPS_ALLOCONLOAD;
349 using_local = local_available;
352 static void GetDirectDraw(void)
354 HRESULT hRes;
356 pWinDisplayDevice = AppGetObj (IWinDisplayDevice);
358 lpdd = NULL;
359 IWinDisplayDevice_GetDirectDraw(pWinDisplayDevice, &lpdd);
360 AssertMsg(lpdd!=NULL, "GetDirectDraw failed");
362 hRes = lpdd->lpVtbl->QueryInterface(lpdd, &IID_IDirectDraw2, (LPVOID *)&lpdd2);
363 CheckHResult(hRes, "Query for DirectDraw2 failed");
367 static void SetTexturePalette(int start, int n, uchar *pal, int slot)
369 PALETTEENTRY peColorTable[256];
370 HRESULT hRes;
371 int i;
373 if (lpDDPalTexture[slot] == NULL)
375 hRes = lpdd->lpVtbl->CreatePalette(lpdd,
376 DDPCAPS_8BIT | DDPCAPS_ALLOW256,
377 peColorTable,
378 &lpDDPalTexture[slot],
379 NULL);
380 CheckHResult(hRes, "CreatePalette failed.");
383 for (i = 0; i < n; i++) {
384 peColorTable[i].peFlags = D3DPAL_READONLY | PC_RESERVED;
385 peColorTable[i].peRed = pal[3*i];
386 peColorTable[i].peGreen = pal[3*i+1];
387 peColorTable[i].peBlue = pal[3*i+2];
390 hRes = lpDDPalTexture[slot]->lpVtbl->SetEntries(lpDDPalTexture[slot],
391 0, start, n, peColorTable);
393 CheckHResult(hRes, "SetEntries failed.");
396 void lgd3d_set_pal_slot(uint start, uint n, uchar *pal_data, int slot)
398 grs_rgb_bitmask bitmask;
400 if (lpdd == NULL)
401 return;
403 if (!texture_RGB)
405 SetTexturePalette(start, n, pal_data, slot);
407 else
409 if (texture_pal[slot]==NULL)
410 texture_pal[slot] = (ushort *)gr_malloc(512);
411 lgd3d_get_texture_bitmask(&bitmask);
412 gr_make_pal16(start, n, texture_pal[slot], pal_data, &bitmask);
416 void lgd3d_set_pal(uint start, uint n, uchar *pal_data)
418 lgd3d_set_pal_slot(start, n, pal_data, 0);
421 static int chroma_r=0;
422 static int chroma_g=0;
423 static int chroma_b=0;
424 static DWORD chroma_key;
426 // values should be 0..255
427 void lgd3d_set_chromakey(int r, int g, int b)
429 chroma_r = r;
430 chroma_g = g;
431 chroma_b = b;
432 if (RGBTextureFormat.dwRBitMask == 0x1f) {
433 // swap red and blue
434 r = chroma_b;
435 b = chroma_r;
437 chroma_key = b>>3;
438 if (RGBTextureFormat.dwGBitMask == GBitMask15) {
439 chroma_key += ((g>>3)<<5) + ((r>>3)<<10);
440 } else {
441 chroma_key += ((g>>2)<<5) + ((r>>3)<<11);
446 static int FindClosestColor(float r, float g, float b)
448 float best=3*256*256;
449 uchar *pal = grd_pal;
450 int i, color = -1;
452 for (i=0; i<256; i++) {
453 float test, dr, dg, db;
454 dr = r - pal[0];
455 dg = g - pal[1];
456 db = b - pal[2];
457 pal += 3;
458 test = dr*dr + db*db + dg*dg;
459 if (test < best) {
460 best = test;
461 color = i;
464 AssertMsg(color>=0,"Couldn't fit color.");
465 return color;
468 static void InitDefaultTexture(int size)
470 grs_bitmap *bm;
471 int c0, c1, i, j;
473 bm = gr_alloc_bitmap(BMT_FLAT8, 0, size, size);
474 c0 = FindClosestColor(180.0, 10.0, 10.0);
475 c1 = FindClosestColor(10.0, 180.0, 10.0);
476 for (i=0; i<size; i++)
477 for (j=0; j<size; j++)
478 bm->bits[size*i+j] = ((i+j)&1) ? c0:c1;
480 default_bm = bm;
483 static void InitTextureList(void)
485 int i;
486 for (i=0; i<LGD3D_MAX_TEXTURES; i++) {
487 Surface[i]=NULL;
488 Texture[i]=NULL;
489 Material[i]=NULL;
490 MaterialHandle[i]=0;
491 TextureHandle[i]=0;
492 TdrvBitmap[i] = NULL;
494 TextureListInited = TRUE;
497 static texture_driver driver;
499 static void CookInfo(tdrv_texture_info *info);
500 static int LoadTexture(tdrv_texture_info *info);
501 static int ReloadTexture(tdrv_texture_info *info);
502 static void ReleaseTexture(int n);
503 static void UnloadTexture(int n);
504 extern void SetTextureId(BOOL t);
505 void SynchD3D(void);
507 static void InitTextureManager(lgd3ds_device_info *info)
509 driver.release_texture = ReleaseTexture;
510 driver.load_texture = LoadTexture;
511 driver.set_texture_id = SetTextureId;
512 driver.unload_texture = UnloadTexture;
513 driver.synchronize = SynchD3D;
514 driver.start_frame = lgd3d_start_frame;
515 driver.end_frame = lgd3d_end_frame;
516 driver.reload_texture = ReloadTexture;
517 driver.cook_info = CookInfo;
519 if (g_tmgr!=NULL) {
520 g_tmgr->shutdown();
521 g_tmgr = NULL;
524 g_tmgr = get_dopey_texture_manager(&driver);
525 g_tmgr->init(
526 default_bm,
527 LGD3D_MAX_TEXTURES,
528 (info->flags & LGD3DF_SPEW) ? TMGRF_SPEW:0);
533 void InitTextureSys(lgd3ds_device_info *info)
535 int i;
537 if (lpdd!=NULL) {
538 Warning(("Texture system already inited.\n"));
539 return;
542 #ifndef SHIP
543 spew = ((info->flags & LGD3DF_SPEW) != 0);
544 #endif
545 device_desc = info->device_desc;
546 texture_caps = device_desc->dpcTriCaps.dwTextureCaps;
547 GetDirectDraw();
548 EnumTextureFormats();
549 for (i=0; i<MAX_PALETTES; i++)
551 texture_pal[i] = NULL;
552 lpDDPalTexture[i] = NULL;
554 lgd3d_set_pal_slot(0,256,grd_pal,0);
555 lgd3d_set_alpha_pal(default_alpha_pal);
556 lgd3d_set_chromakey(chroma_r, chroma_g, chroma_b);
557 InitTextureList();
558 pWinDisplayDevice->lpVtbl->AddTaskSwitchCallback(
559 pWinDisplayDevice, CheckSurfaces);
560 InitDefaultTexture(16);
561 InitTextureManager(info);
566 /***************************************************************************/
567 /* Loading a grs_bitmap into a system memory surface */
568 /***************************************************************************/
570 * LoadSurface
571 * Loads a grs_bitmap into a texture map DD surface of the given format. The
572 * memory flag specifies DDSCAPS_SYSTEMMEMORY or DDSCAPS_VIDEOMEMORY.
575 static HRESULT CreateSurface(d3d_cookie cookie, DDSURFACEDESC *ddsd, LPDIRECTDRAWSURFACE *ppDDS)
577 DDCOLORKEY ck;
578 HRESULT ddrval;
579 LPDIRECTDRAWSURFACE pDDS;
580 DWORD ckey;
582 ddrval = lpdd->lpVtbl->CreateSurface(lpdd, ddsd, ppDDS, NULL);
583 if (ddrval != DD_OK)
584 return ddrval;
586 pDDS = *ppDDS;
588 // Bind the palette, if necessary
589 if (ddsd->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
590 ddrval = pDDS->lpVtbl->SetPalette(pDDS, lpDDPalTexture[cookie.palette]);
591 CheckHResult(ddrval, "SetPalette failed while creating surface.");
592 ckey = 0;
593 } else
594 ckey = chroma_key;
596 // Set colorkey, if necessary
597 if (PF_TRANS & cookie.flags) {
598 ck.dwColorSpaceLowValue = ckey;
599 ck.dwColorSpaceHighValue = ckey;
600 ddrval = pDDS->lpVtbl->SetColorKey(pDDS, DDCKEY_SRCBLT, &ck);
601 CheckHResult(ddrval, "SetColorKey failed while creating surface.");
604 return DD_OK;
608 // OK, here are our various specialized blitters
610 static void blit_8to16(tdrv_texture_info *info, ushort *dst, int drow, ushort *pal)
612 int i, j;
613 grs_bitmap *bm = info->bm;
614 uchar *src = info->bits;
616 for (i=0; i<bm->h; i++) {
617 for (j=0; j<bm->w; j++)
618 dst[j] = pal[src[j]];
619 src += bm->row;
620 dst += drow;
624 static void blit_8to16_clut(tdrv_texture_info *info, ushort *dst, int drow, ushort *pal)
626 int i, j;
627 grs_bitmap *bm = info->bm;
628 uchar *src = info->bits;
630 for (i=0; i<bm->h; i++) {
631 for (j=0; j<bm->w; j++)
632 dst[j] = pal[texture_clut[src[j]]];
633 src += bm->row;
634 dst += drow;
638 static void blit_8to16_scale(tdrv_texture_info *info, ushort *dst, int drow, ushort *pal)
640 int i, j, k;
641 int scale_w = info->scale_w;
642 int scale_h = info->scale_h;
643 int step_w = 1<<(scale_w-1);
644 int step_h = (1<<scale_h)-1;
645 grs_bitmap *bm = info->bm;
646 uchar *src = info->bits;
648 for (i=0; i<bm->h; i++) {
649 if (scale_w>0)
651 ulong *base = (ulong *)dst;
652 for (j=0; j<bm->w; j++)
654 ulong c32 = pal[src[j]];
655 c32 += (c32<<16);
656 for (k=0; k<step_w; k++)
657 base[k] = c32;
658 base += step_w;
660 } else {
661 for (j=0; j<bm->w; j++)
662 dst[j] = pal[src[j]];
664 for (j=0; j<step_h; j++) {
665 memcpy(dst + drow, dst, 2*(bm->w<<scale_w));
666 dst += drow;
668 src += bm->row;
669 dst += drow;
673 static void blit_8to16_clut_scale(tdrv_texture_info *info, ushort *dst, int drow, ushort *pal)
675 int i, j, k;
676 int scale_w = info->scale_w;
677 int scale_h = info->scale_h;
678 int step_w = 1<<(scale_w-1);
679 int step_h = (1<<scale_h)-1;
680 grs_bitmap *bm = info->bm;
681 uchar *src = info->bits;
683 for (i=0; i<bm->h; i++) {
684 if (scale_w>0)
686 ulong *base = (ulong *)dst;
687 for (j=0; j<bm->w; j++)
689 ulong c32 = pal[texture_clut[src[j]]];
690 c32 += (c32<<16);
691 for (k=0; k<step_w; k++)
692 base[k] = c32;
693 base += step_w;
695 } else {
696 for (j=0; j<bm->w; j++)
697 dst[j] = pal[texture_clut[src[j]]];
699 for (j=0; j<step_h; j++) {
700 memcpy(dst + drow, dst, 2*(bm->w<<scale_w));
701 dst += drow;
703 src += bm->row;
704 dst += drow;
709 static void blit_8to8(tdrv_texture_info *info, uchar *dst, int drow)
711 int i;
712 grs_bitmap *bm = info->bm;
713 uchar *src = info->bits;
715 for (i=0; i<bm->h; i++) {
716 memcpy(dst, src, bm->w);
717 src += bm->row;
718 dst += drow;
722 static void blit_8to8_clut(tdrv_texture_info *info, uchar *dst, int drow)
724 int i, j;
725 grs_bitmap *bm = info->bm;
726 uchar *src = info->bits;
728 for (i=0; i<bm->h; i++) {
729 for (j=0; j<bm->w; j++)
730 dst[j] = texture_clut[src[j]];
731 src += bm->row;
732 dst += drow;
736 static void blit_8to8_scale(tdrv_texture_info *info, uchar *dst, int drow)
738 int i, j, k;
739 int scale_w = info->scale_w;
740 int scale_h = info->scale_h;
741 int step_w = 1<<scale_w;
742 int step_h = (1<<scale_h) - 1;
743 grs_bitmap *bm = info->bm;
744 uchar *src = info->bits;
746 for (i=0; i<bm->h; i++) {
747 if (scale_w > 0) {
748 uchar *base = dst;
749 for (j=0; j<bm->w; j++) {
750 uchar c = src[j];
751 for (k=0; k<step_w; k++)
752 base[k] = c;
753 base += step_w;
755 } else
756 memcpy(dst, src, bm->w);
757 for (j = 0; j<step_h; j++) {
758 memcpy(dst + drow, dst, bm->w);
759 dst += drow;
761 src += bm->row;
762 dst += drow;
766 static void blit_8to8_clut_scale(tdrv_texture_info *info, uchar *dst, int drow)
768 int i, j, k;
769 int scale_w = info->scale_w;
770 int scale_h = info->scale_h;
771 int step_w = 1<<scale_w;
772 int step_h = (1<<scale_h) - 1;
773 grs_bitmap *bm = info->bm;
774 uchar *src = info->bits;
776 for (i=0; i<bm->h; i++) {
777 uchar *base = dst;
778 for (j=0; j<bm->w; j++) {
779 uchar c = texture_clut[src[j]];
780 for (k=0; k<step_w; k++)
781 base[k] = c;
782 base += step_w;
784 for (j = 0; j<step_h; j++) {
785 memcpy(dst + drow, dst, bm->w);
786 dst += drow;
788 src += bm->row;
789 dst += drow;
794 static void blit_16to16(tdrv_texture_info *info, ushort *dst, int drow)
796 int i;
797 grs_bitmap *bm = info->bm;
798 uchar *src = info->bits;
800 for (i=0; i<bm->h; i++) {
801 memcpy(dst, src, 2*bm->w);
802 src += bm->row;
803 dst += drow;
808 static void blit_16to16_scale(tdrv_texture_info *info, ushort *dst, int drow)
810 int i, j, k;
811 int scale_w = info->scale_w;
812 int scale_h = info->scale_h;
813 int step_w = 1<<scale_w;
814 int step_h = (1<<scale_h) - 1;
815 grs_bitmap *bm = info->bm;
816 int srow = bm->row>>1;
817 ushort *src = (ushort *)info->bits;
819 for (i=0; i<bm->h; i++) {
820 if (step_w > 1) {
821 ushort *base = dst;
822 for (j=0; j<bm->w; j++) {
823 ushort c = src[j];
824 for (k=0; k<step_w; k++)
825 base[k] = c;
826 base += step_w;
828 } else
829 memcpy(dst, src, 2*bm->w);
830 for (j = 0; j<step_h; j++) {
831 memcpy(dst + drow, dst, 2*bm->w);
832 dst += drow;
834 src += srow;
835 dst += drow;
840 static void LoadSurface(tdrv_texture_info *info, DDSURFACEDESC *ddsd)
842 uchar *src;
843 grs_bitmap *bm = info->bm;
844 int flags = info->flags;
845 uchar zero_save = 0;
847 if ((texture_clut != NULL) && (bm->flags & BMF_TRANS))
849 zero_save = texture_clut[0];
850 texture_clut[0] = 0;
853 if (ddsd->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
854 uchar *dst = (uchar *)ddsd->lpSurface;
855 if ((info->scale_w|info->scale_h) != 0)
856 if (texture_clut!=NULL)
857 blit_8to8_clut_scale(info, dst, ddsd->lPitch);
858 else
859 blit_8to8_scale(info, dst, ddsd->lPitch);
860 else
861 if (texture_clut!=NULL)
862 blit_8to8_clut(info, dst, ddsd->lPitch);
863 else
864 blit_8to8(info, dst, ddsd->lPitch);
865 } else {
866 ushort *dst = (ushort *)ddsd->lpSurface;
867 int drow = ddsd->lPitch/2;
869 if (bm->type == BMT_FLAT8) {
870 ushort *pal;
871 ushort zero_save;
873 pal = (flags & TF_ALPHA) ? alpha_pal : texture_pal[bm->align];
874 if (pal==NULL)
875 pal = grd_pal16_list[0];
877 if (flags & TF_TRANS) {
878 zero_save = pal[0];
879 pal[0] = chroma_key;
882 AssertMsg(pal!=NULL, "Hey! trying to use NULL 16 bit palette to load texture!");
883 src = bm->bits;
885 if ((info->scale_w|info->scale_h) != 0)
886 if ((flags & TF_ALPHA)||(texture_clut == NULL))
887 blit_8to16_scale(info, dst, drow, pal);
888 else
889 blit_8to16_clut_scale(info, dst, drow, pal);
890 else
891 if ((flags & TF_ALPHA)||(texture_clut == NULL))
892 blit_8to16(info, dst, drow, pal);
893 else
894 blit_8to16_clut(info, dst, drow, pal);
896 if (flags & TF_TRANS)
897 pal[0] = zero_save;
899 } else { // assume straight 16 to 16
900 if ((info->scale_w|info->scale_h) != 0)
901 blit_16to16_scale(info, dst, drow);
902 else
903 blit_16to16(info, dst, drow);
906 if (zero_save!=0)
907 texture_clut[0] = zero_save;
910 static void GetAvailableTexMem(DWORD *local, DWORD *agp)
912 DDSCAPS ddscaps;
913 DWORD total;
915 AssertMsg(NULL!=lpdd2, "No DirectDraw object!");
917 if (local!=NULL) {
918 ddscaps.dwCaps = LOCAL_CAPS;
919 lpdd2->lpVtbl->GetAvailableVidMem(lpdd2, &ddscaps, &total, local);
921 if (agp!=NULL) {
922 ddscaps.dwCaps = NONLOCAL_CAPS;
923 lpdd2->lpVtbl->GetAvailableVidMem(lpdd2, &ddscaps, &total, agp);
928 static void CookInfo(tdrv_texture_info *info)
930 d3d_cookie cookie;
931 int v, w=info->w, h=info->h;
933 cookie.hlog = 0;
934 cookie.wlog = 0;
935 for (v=2; v<=w; v+=v)
937 cookie.wlog++;
939 for (v=2; v<=h; v+=v)
941 cookie.hlog++;
944 AssertMsg((info->h == (1<<cookie.hlog)) && (info->w == (1<<cookie.wlog)),
945 "hlog/wlog does not match texture width/height");
947 if (info->flags & TF_ALPHA)
948 cookie.flags = PF_ALPHA;
949 else if (info->bm->type == BMT_FLAT16)
950 cookie.flags = PF_RGB;
951 else
952 cookie.flags = PF_GENERIC;
954 if (info->flags & TF_TRANS)
955 cookie.flags |= PF_TRANS;
957 if (info->bm->type == BMT_FLAT8)
958 cookie.palette = info->bm->align;
959 else
960 cookie.palette = 0;
962 info->cookie = cookie.value;
966 static int ReloadTexture(tdrv_texture_info *info)
968 LPDDPIXELFORMAT pixel_format;
969 DDSURFACEDESC ddsd;
970 LPDIRECTDRAWSURFACE SysmemSurface, *pDeviceSurface;
971 LPD3DITEXTURE SysmemTexture=NULL, *pDeviceTexture;
972 HRESULT LastError;
973 d3d_cookie cookie;
975 put_mono('b');
977 pDeviceTexture = &Texture[info->id];
978 pDeviceSurface = &Surface[info->id];
980 SynchD3D();
982 cookie.value = info->cookie;
983 pixel_format = FormatList[cookie.flags&PF_MASK];
985 if (pixel_format->dwFlags==0)
986 // unsupported texture format
987 return TDRV_FAILURE;
989 // Create a surface of the given format using the dimensions of the grs_bitmap
991 ZeroMemory(&ddsd, sizeof(ddsd));
993 ddsd.dwSize = sizeof(DDSURFACEDESC);
994 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
995 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
996 memcpy(&ddsd.ddpfPixelFormat, pixel_format, sizeof(ddsd.ddpfPixelFormat));
997 ddsd.dwHeight = info->h;
998 ddsd.dwWidth = info->w;
1000 put_mono('c');
1002 LastError = CreateSurface(cookie, &ddsd, &SysmemSurface);
1003 CheckHResult(LastError, "CreateSurface() failed");
1004 AssertMsg(SysmemSurface!=NULL, "NULL SysmemSurface");
1005 put_mono('h');
1006 LastError = SysmemSurface->lpVtbl->QueryInterface(SysmemSurface,
1007 &IID_ID3DTexture,
1008 (LPVOID*)&SysmemTexture);
1010 CheckHResult(LastError, "Failed to obtain D3D texture interface for sysmem surface");
1012 ddsd.dwSize = sizeof(DDSURFACEDESC);
1013 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1017 put_mono('i');
1018 if (*pDeviceTexture == NULL) {
1019 LPDIRECTDRAWSURFACE DeviceSurface;
1021 ddsd.ddsCaps.dwCaps = DeviceSurfaceCaps;
1022 LastError = CreateSurface(cookie, &ddsd, pDeviceSurface);
1023 if ((LastError!=DD_OK) && using_local && agp_available)
1025 mono_printf(("using nonlocal vidmem textures...\n"));
1026 // try AGP textures...
1027 using_local = FALSE;
1028 DeviceSurfaceCaps = NONLOCAL_CAPS;
1029 ddsd.ddsCaps.dwCaps = DeviceSurfaceCaps;
1030 LastError = CreateSurface(cookie, &ddsd, pDeviceSurface);
1033 if (LastError!=DD_OK) {
1034 mono_printf(("couldn't load texture: error %i.\n", LastError&0xffff));
1035 SafeRelease(SysmemTexture);
1036 SafeRelease(SysmemSurface);
1037 *pDeviceSurface = NULL;
1038 put_mono('.');
1039 return TDRV_FAILURE;
1042 DeviceSurface = *pDeviceSurface;
1044 #define MEMORY_TYPE_MASK \
1045 (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY|DDSCAPS_LOCALVIDMEM|DDSCAPS_NONLOCALVIDMEM)
1047 if ((DeviceSurfaceCaps&MEMORY_TYPE_MASK) != (ddsd.ddsCaps.dwCaps&MEMORY_TYPE_MASK))
1048 mono_printf((
1049 "device texture not created in requested memory location\nRequested %x Received %x\n",
1050 DeviceSurfaceCaps&MEMORY_TYPE_MASK, ddsd.ddsCaps.dwCaps&MEMORY_TYPE_MASK));
1053 // Query our device surface for a texture interface
1054 put_mono('k');
1055 LastError = DeviceSurface->lpVtbl->QueryInterface(DeviceSurface,
1056 &IID_ID3DTexture,
1057 (LPVOID*)pDeviceTexture);
1058 CheckHResult(LastError, "Failed to obtain D3D texture interface for device surface.");
1061 // Load the bitmap into the sysmem surface
1062 LastError = SysmemSurface->lpVtbl->Lock(SysmemSurface, NULL, &ddsd, 0, NULL);
1063 CheckHResult(LastError, "Failed to lock sysmem surface.");
1065 LoadSurface(info, &ddsd);
1067 LastError = SysmemSurface->lpVtbl->Unlock(SysmemSurface, NULL);
1068 CheckHResult(LastError, "Failed to unlock sysmem surface.");
1070 // Load the sysmem texture into the device texture. During this call, a
1071 // driver could compress or reformat the texture surface and put it in
1072 // video memory.
1074 put_mono('l');
1075 LastError = pDeviceTexture[0]->lpVtbl->Load(pDeviceTexture[0], SysmemTexture);
1076 CheckHResult(LastError, "Failed to load device texture from sysmem texture.");
1078 // Now we are done with sysmem surface
1080 put_mono('m');
1081 SafeRelease(SysmemTexture);
1082 put_mono('n');
1083 SafeRelease(SysmemSurface);
1085 TdrvBitmap[info->id] = info->bm;
1087 put_mono('.');
1088 return TDRV_SUCCESS;
1091 static int doLoad(tdrv_texture_info *info)
1093 HRESULT LastError;
1094 int result;
1095 int n = info->id;
1097 result = ReloadTexture(info);
1098 if (result != TDRV_SUCCESS)
1099 return result;
1101 put_mono('o');
1102 LastError = Texture[n]->lpVtbl->GetHandle(Texture[n], lpd3dDevice, &TextureHandle[n]);
1104 if (LastError!=DD_OK) {
1105 mono_printf(("GetTextureHandle failed! facility %i error %i width %i height %i\n",
1106 (LastError>>16)&0x7fff, LastError&0xffff, info->w, info->h));
1107 SafeRelease(Texture[n]);
1108 SafeRelease(Surface[n]);
1109 put_mono('.');
1110 return TDRV_FAILURE;
1113 return TDRV_SUCCESS;
1117 static int LoadTexture(tdrv_texture_info *info)
1119 int n = info->id;
1120 DWORD local_start=0, agp_start=0;
1121 int result;
1123 put_mono('a');
1125 #if 0
1126 if ((info->h < device_desc->dwMinTextureHeight) ||
1127 (info->h > device_desc->dwMaxTextureHeight) ||
1128 (info->w < device_desc->dwMinTextureWidth) ||
1129 (info->w > device_desc->dwMaxTextureWidth))
1130 return TDRV_FAILURE;
1131 #endif
1132 if ((texture_caps & D3DPTEXTURECAPS_SQUAREONLY) && (info->w != info->h)) {
1133 put_mono('.');
1134 return TDRV_FAILURE;
1137 GetAvailableTexMem(
1138 local_available ? &local_start : NULL,
1139 agp_available ? &agp_start : NULL);
1141 if ((local_start < info->size) && using_local && agp_available)
1142 { // switch to agp and try again...
1143 mono_printf(("using nonlocal vidmem textures...\n"));
1145 using_local = FALSE;
1146 DeviceSurfaceCaps = NONLOCAL_CAPS;
1149 if ((using_local ? local_start : agp_start) < info->size)
1151 put_mono('.');
1152 return TDRV_FAILURE;
1155 AssertMsg((n>=0)&&(n<LGD3D_MAX_TEXTURES), "Texture id out of range");
1157 // These should already be taken care of, but just in case...
1158 SafeRelease(Material[n]);
1159 SafeRelease(Texture[n]);
1160 SafeRelease(Surface[n]);
1161 TextureHandle[n]=0;
1162 MaterialHandle[n]=0;
1164 result = doLoad(info);
1165 put_mono('p');
1166 if ((result != TDRV_SUCCESS) && using_local && agp_available) {
1167 // switch to AGP and try again...
1168 mono_printf(("using nonlocal vidmem textures...\n"));
1170 using_local = FALSE;
1171 DeviceSurfaceCaps = NONLOCAL_CAPS;
1172 result = doLoad(info);
1175 if (result != TDRV_SUCCESS) {
1176 put_mono('.');
1177 return result;
1180 InitMaterial(n);
1182 // calculate load size if requested
1183 if (info->size == 0) {
1184 DWORD local_end, agp_end;
1186 // calculate size
1187 GetAvailableTexMem(
1188 local_available ? &local_end : NULL,
1189 agp_available ? &agp_end : NULL);
1191 if (local_available && (local_start > local_end))
1193 AssertMsg( (!agp_available)||(agp_start==agp_end),
1194 "Texture load modified local and nonlocal vidmem!");
1195 info->size = local_start - local_end;
1196 } else {
1197 AssertMsg(agp_available && (agp_start > agp_end),
1198 "Texture load took no space!");
1199 info->size = agp_start - agp_end;
1203 put_mono('.');
1204 return TDRV_SUCCESS;
1207 static void CheckSurfaces(sWinDispDevCallbackInfo *info)
1209 static void (*chain)(sWinDispDevCallbackInfo *);
1210 int i;
1212 switch (info->message) {
1213 case kWinDispDevCallbackActive:
1214 for (i=0; i<LGD3D_MAX_TEXTURES; i++) {
1215 LPDIRECTDRAWSURFACE lpTS = Surface[i];
1216 if ((lpTS == NULL)||
1217 (lpTS->lpVtbl->IsLost(lpTS) != DDERR_SURFACELOST))
1218 continue;
1220 VerifyMsg(lpTS->lpVtbl->Restore(lpTS)==DD_OK, "Could not restore lost surface!");
1221 if (TdrvBitmap[i]!=NULL) {
1222 AssertMsg(g_tmgr != NULL, "Hmmm. Should have a non-NULL texture manager here.");
1223 g_tmgr->unload_texture(TdrvBitmap[i]);
1226 break;
1227 case kWinDispDevCallbackUpdateChain:
1228 GenericCallbackChainHandler(&callback_id, (callback_chain_func **)&chain, (callback_chain_info *)info);
1229 return;
1231 if (chain!=NULL)
1232 chain(info);
1235 extern void UnsetTextureId(int n);
1236 // Disconnect texture from bitmap, but don't release texture yet
1237 static void UnloadTexture(int n)
1239 AssertMsg((n>=0)&&(n<LGD3D_MAX_TEXTURES), "Texture id out of range");
1240 TdrvBitmap[n] = NULL;
1243 static void ReleaseTexture(int n)
1245 AssertMsg((n>=0)&&(n<LGD3D_MAX_TEXTURES), "Texture id out of range");
1246 UnsetTextureId(n);
1247 Assert(Surface[n]!=NULL, ("texture %i already released\n", n));
1249 if ((Surface[n]!=NULL) && local_available && (!using_local))
1251 DDSCAPS ddscaps;
1252 Surface[n]->lpVtbl->GetCaps(Surface[n], &ddscaps);
1253 if (ddscaps.dwCaps & DDSCAPS_LOCALVIDMEM)
1255 mono_printf(("Using Local vidmem textures\n"));
1256 DeviceSurfaceCaps = LOCAL_CAPS;
1257 using_local = TRUE;
1261 SafeRelease(Material[n]);
1262 SafeRelease(Texture[n]);
1263 SafeRelease(Surface[n]);
1264 MaterialHandle[n]=0;
1265 TextureHandle[n]=0;
1266 TdrvBitmap[n] = NULL;
1269 void SynchD3D(void)
1271 #ifndef SHIP
1272 HRESULT hRes =
1273 #endif
1274 lpd3dDevice->lpVtbl->SetRenderState(lpd3dDevice,
1275 D3DRENDERSTATE_FLUSHBATCH, 0);
1276 CheckHResult(hRes, "FlushBatch failed");