/*===========================================================================*/ /* */ /* Mesa-3.0 DirectX 6 Driver */ /* */ /* By Leigh McRae */ /* */ /* http://www.altsoftware.com/ */ /* */ /* Copyright (c) 1999-1998 alt.software inc. All Rights Reserved */ /*===========================================================================*/ #include "D3DHAL.h" /*===========================================================================*/ /* Local function prototypes. */ /*===========================================================================*/ static void UpdateTexture( PTM_OBJECT pTMObj, BOOL bVideo, RECT *pRect, UCHAR *pixels ); static BOOL LoadTextureInVideo( PMESAD3DHAL pHAL, PTM_OBJECT pTMObj ); static BOOL FreeTextureMemory( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject ); static BOOL DestroyTextureObject( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject ); HRESULT CALLBACK EnumPFHook( LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext ); /*===========================================================================*/ /* This function will simply set the top of stack to NULL. I only used it */ /* just incase I want to add something later. */ /*===========================================================================*/ /* RETURN: TRUE. */ /*===========================================================================*/ BOOL InitTMgrHAL( PMESAD3DHAL pHAL ) { DPF(( DBG_FUNC, "InitTMgrHAL();" )); /* Be clean my friend. */ pHAL->pTMList = NULL; return TRUE; } /*===========================================================================*/ /* This function will walk the Texture Managers linked list and destroy all */ /* surfaces (SYSTEM/VIDEO). The texture objects themselves also will be */ /* freed. */ /* NOTE: this is per/context. */ /*===========================================================================*/ /* RETURN: */ /*===========================================================================*/ void TermTMgrHAL( PMESAD3DHAL pHAL ) { DPF(( DBG_FUNC, "TermTMgrHAL();" )); if ( pHAL && pHAL->pTMList ) { /* Destroy the surface and remove the TMO from the stack. */ while( DestroyTextureObject(pHAL,NULL) ); /* Be clean my friend. */ pHAL->pTMList = NULL; } } /*===========================================================================*/ /* This function is a HACK as I don't know how I can disable a texture with-*/ /* out booting it out. Is there know state change? */ /*===========================================================================*/ /* RETURN: */ /*===========================================================================*/ extern "C" void DisableTMgrHAL( PMESAD3DSHARED pShared ) { PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared; DPF(( DBG_FUNC, "DisableTMgrHAL();" )); /* Check too see that we have a valid context. */ if ( (pHAL == NULL) && (pHAL->lpD3DDevice != NULL) ) { DPF(( DBG_TXT_WARN, "Null HAL/Direct3D Device!" )); return; } // TODO: This is a hack to shut off textures. pHAL->lpD3DDevice->SetTexture( 0, NULL ); } /*===========================================================================*/ /* This function is the only entry into the TextureManager that Mesa/wgl */ /* will see. It uses a dwAction to specify what we are doing. I did this as*/ /* depending on the cards resources the action taken can change. */ /* When this function is called we will always search the Texture Managers */ /* linked list (per context remember) and try and find a structure that has */ /* the same dwName. If we have a match we pull it out of the list and put it*/ /* at the top of the list (TOL). If we don't find one then we create a struc*/ /* and put it a TOL. This TOL idea makes for some caching as we will always */ /* destroy Texture Surfaces from the bottom up... */ /* All texture objects at this point will create a texture surface in System*/ /* memory (SMEM). Then we will copy the Mesa texture into the surface using */ /* the 'pixel' struc to get the translation info. So now this means that all*/ /* textures that Mesa gives me I will have a Surface with a copy. If Mesa */ /* changes the texture the I update the surface in (SMEM). */ /* Now we have a texture struc and a Texture Surface in SMEM. At this point*/ /* we create another surface on the card (VMEM). Finally we blt from the */ /* SMEM to the VMEM and set the texture as current. Why do I need two? First*/ /* this solves square textures. If the cards CAPS is square textures only */ /* then I change the dimensions of the VMEM surface and the blt solves it for*/ /* me. Second it saves me from filling D3D textures over and over if the */ /* card needs to be creating and destroying surfaces because of low memory. */ /* The surface in SMEM is expected to work always. When a surface has to be*/ /* created in VMEM then we put it in a loop that tries to create the surface.*/ /* If we create the surface ok then we brake from the loop. If we fail then */ /* we will call 'FreeTextureMemory' that will return TRUE/FALSE as to whether*/ /* memory was freed. If memory was freed then we can try again. If no memory*/ /* was freed then it just can't fit. */ /* 'FreeTextureMemory' will find the end of the list and start freeing VMEM */ /* (never SMEM) surfaces that are not locked. */ /* BIND - when we bind and there is a texture struct with a texture surface */ /* in VMEM then we just make it current. If we have a struct and a surface */ /* in SMEM but no VMEM surface then we create the surface in VMEM and blt */ /* from the SMEM surface. If we have nothing its just like a creation... */ /*===========================================================================*/ /* RETURN: TRUE, FALSE. */ /*===========================================================================*/ extern "C" BOOL CreateTMgrHAL( PMESAD3DSHARED pShared, DWORD dwName, int level, DWORD dwRequestFlags, RECT *rectDirty, DWORD dwWidth, DWORD dwHeight, DWORD dwAction, void *pPixels ) { PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared; PTM_OBJECT pTMObj, pTemp; DDSURFACEDESC2 ddsd2; HRESULT rc; DPF(( DBG_FUNC, "CreateTMgrHAL();" )); DPF(( DBG_TXT_INFO, "Texture:" )); DPF(( DBG_TXT_INFO, "cx: %d cy: %d", dwWidth, dwHeight )); DPF(( DBG_TXT_INFO, "Rect:" )); if ( rectDirty ) { DPF(( DBG_TXT_INFO, "x0: %d y0: %d", rectDirty->left, rectDirty->top )); DPF(( DBG_TXT_INFO, "x1: %d y1: %d", rectDirty->right, rectDirty->bottom )); } /* Check too see that we have a valid context. */ if ( (pHAL == NULL) && (pHAL->lpD3DDevice != NULL) ) { DPF(( DBG_TXT_WARN, "Null HAL/Direct3D Device!" )); return FALSE; } /*=================================================*/ /* See if we can find this texture object by name. */ /*=================================================*/ for( pTMObj = pHAL->pTMList; pTMObj && (pTMObj->dwName != dwName); pTMObj = pTMObj->next ); /*=========================================================*/ /* Allocate a new object if we didn't get a matching name. */ /*=========================================================*/ if ( pTMObj == NULL ) { pTMObj = (PTM_OBJECT)ALLOC( sizeof(TM_OBJECT) ); if ( pTMObj == NULL ) return FALSE; memset( pTMObj, 0, sizeof(TM_OBJECT) ); /* Put the object at the beginning of the list. */ pTMObj->next = pHAL->pTMList; if ( pTMObj->next ) { pTemp = pTMObj->next; pTemp->prev = pTMObj; } pHAL->pTMList = pTMObj; } else { /*===============================================================*/ /* Make some caching happen by pulling this object to the front. */ /*===============================================================*/ if ( pHAL->pTMList != pTMObj ) { /* Pull the object out of the list. */ if ( pTMObj->prev ) { pTemp = pTMObj->prev; pTemp->next = pTMObj->next; } if ( pTMObj->next ) { pTemp = pTMObj->next; pTemp->prev = pTMObj->prev; } pTMObj->prev = NULL; pTMObj->next = NULL; /* Put the object at the front of the list. */ pTMObj->next = pHAL->pTMList; if ( pTMObj->next ) { pTemp = pTMObj->next; pTemp->prev = pTMObj; } pHAL->pTMList = pTMObj; } } /*========================================================*/ /* If we are doing BIND and the texture is in VID memory. */ /*========================================================*/ if ( (dwAction == TM_ACTION_BIND) && pTMObj->lpDDS_Video ) { DPF(( DBG_TXT_PROFILE, "Cache HIT (%d)", dwName )); /* Make this the current texture. */ rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 ); if ( FAILED(rc) ) { DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) )); pHAL->lpD3DDevice->SetTexture( 0, NULL ); return FALSE; } return TRUE; } /*=================================================================*/ /* If we are doing BIND and the texture is at least in SYS memory. */ /*=================================================================*/ if ( (dwAction == TM_ACTION_BIND) && pTMObj->lpDDS_System ) { DPF(( DBG_TXT_PROFILE, "Cache MISS (%d)", dwName )); /* Create the texture on the card. */ rc = LoadTextureInVideo( pHAL, pTMObj ); if ( rc == FALSE ) return FALSE; /* Make this the current texture. */ rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 ); if ( FAILED(rc) ) { DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) )); pHAL->lpD3DDevice->SetTexture( 0, NULL ); return FALSE; } return TRUE; } /*=========================================================*/ /* If we are doing UPDATE then try in VID first for speed. */ /*=========================================================*/ if ( (dwAction == TM_ACTION_UPDATE) && pTMObj->lpDDS_Video && !(pHAL->D3DHWDevDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) ) { DPF(( DBG_TXT_INFO, "Fix the SubTexture update Leigh!" )); /* Update the texture on the card. */ UpdateTexture( pTMObj, TRUE, rectDirty, (UCHAR *)pPixels ); /* We updated the texture in VID so kill the SYS so we know its dirty. */ if ( pTMObj->lpDDS_System ) { DPF(( DBG_TXT_INFO, "Release texture (SYS)" )); DX_RESTORE( pTMObj->lpDDS_System ); pTMObj->lpDDS_System->Release(); pTMObj->lpDDS_System = NULL; } /* Make this the current texture. */ rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 ); if ( FAILED(rc) ) { DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) )); pHAL->lpD3DDevice->SetTexture( 0, NULL ); return FALSE; } return TRUE; } /*===========================================================*/ /* If we are doing UPDATE then try in SYS still gives speed. */ /*===========================================================*/ if ( (dwAction == TM_ACTION_UPDATE) && pTMObj->lpDDS_System ) { DPF(( DBG_TXT_INFO, "Fix the SubTexture update Leigh!" )); /* Update the texture in SYS. */ UpdateTexture( pTMObj, FALSE, NULL, (UCHAR *)pPixels ); /* We updated the SYS texture only so now blt to the VID. */ rc = LoadTextureInVideo( pHAL, pTMObj ); if ( rc == FALSE ) return FALSE; /* Make this the current texture. */ rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 ); if ( FAILED(rc) ) { DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) )); pHAL->lpD3DDevice->SetTexture( 0, NULL ); return FALSE; } return TRUE; } /* At this point we have a valid Texture Manager Object with updated */ /* links. We now need to create or update a texture surface that is */ /* in system memory. Every texture has a copy in system so we can use*/ /* blt to solve problems with textures allocated on the card (square */ /* only textures, pixelformats...). */ // TODO: make support for update also. Dirty rectangle basicly... /* Kill the interface if we have one no matter what. */ if ( pTMObj->lpD3DTexture2 ) { DPF(( DBG_TXT_INFO, "Release Texture2" )); pTMObj->lpD3DTexture2->Release(); pTMObj->lpD3DTexture2 = NULL; } /* Kill the system surface. TODO: should try to get the SubIMage going again */ if ( pTMObj->lpDDS_System ) { DPF(( DBG_TXT_INFO, "Release texture (SYS)" )); DX_RESTORE( pTMObj->lpDDS_System ); pTMObj->lpDDS_System->Release(); pTMObj->lpDDS_System = NULL; } /* Kill the Video surface. TODO: need some reuse system... */ if ( pTMObj->lpDDS_Video ) { DPF(( DBG_TXT_INFO, "Release texture (VID)" )); DX_RESTORE( pTMObj->lpDDS_Video ); pTMObj->lpDDS_Video->Release(); pTMObj->lpDDS_Video = NULL; } /*================================================================*/ /* Translate the the Mesa/OpenGL pixel channels to the D3D flags. */ /*================================================================*/ switch( dwRequestFlags ) { case GL_ALPHA: dwRequestFlags = DDPF_ALPHA; DPF(( DBG_TXT_WARN, "GL_ALPHA not supported!)" )); return FALSE; case GL_INTENSITY: case GL_LUMINANCE: DPF(( DBG_TXT_WARN, "GL_INTENSITY/GL_LUMINANCE not supported!)" )); dwRequestFlags = DDPF_LUMINANCE; return FALSE; case GL_LUMINANCE_ALPHA: DPF(( DBG_TXT_WARN, "GL_LUMINANCE_ALPHA not supported!)" )); dwRequestFlags = DDPF_LUMINANCE | DDPF_ALPHAPIXELS; return FALSE; case GL_RGB: DPF(( DBG_TXT_INFO, "Texture -> GL_RGB" )); dwRequestFlags = DDPF_RGB; break; case GL_RGBA: DPF(( DBG_TXT_INFO, "Texture -> GL_RGBA" )); dwRequestFlags = DDPF_RGB | DDPF_ALPHAPIXELS; break; } /*==============================*/ /* Populate the texture object. */ /*==============================*/ pTMObj->dwName = dwName; pTMObj->lpD3DDevice = pHAL->lpD3DDevice; pTMObj->dwFlags = dwRequestFlags; if ( pHAL->D3DHWDevDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY ) { DPF(( DBG_TXT_INFO, "Convert to Square..." )); pTMObj->dwSHeight = dwHeight; pTMObj->dwSWidth = dwWidth; /* Shrink non-square textures. */ pTMObj->dwVHeight = (dwHeight > dwWidth) ? dwWidth : dwHeight; pTMObj->dwVWidth = (dwHeight > dwWidth) ? dwWidth : dwHeight; } else { pTMObj->dwSHeight = dwHeight; pTMObj->dwSWidth = dwWidth; pTMObj->dwVHeight = dwHeight; pTMObj->dwVWidth = dwWidth; } /*========================*/ /* Create SYSTEM surface. */ /*========================*/ /* Request a surface in system memory. */ memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) ); ddsd2.dwSize = sizeof( DDSURFACEDESC2 ); ddsd2.dwWidth = pTMObj->dwSWidth; ddsd2.dwHeight = pTMObj->dwSHeight; ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; ddsd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY; ddsd2.ddsCaps.dwCaps2 = 0L; memset( &ddsd2.ddpfPixelFormat, 0, sizeof(DDPIXELFORMAT) ); ddsd2.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT ); ddsd2.ddpfPixelFormat.dwFlags = dwRequestFlags; rc = pHAL->lpD3DDevice->EnumTextureFormats( EnumPFHook, &ddsd2.ddpfPixelFormat ); if ( FAILED(rc) ) { RIP( pHAL, "EnumerTextureFormats (SYSTEM)->", ErrorStringD3D(rc) ); return FALSE; } /* Create the surface using the enumerated pixelformat. */ rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pTMObj->lpDDS_System, NULL ); if ( FAILED(rc) ) { RIP( pHAL, "CreateSurface (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) ); return FALSE; } /* Solve the pixel mapping info using the surface pixelformat. */ Solve8BitChannelPixelFormat( &ddsd2.ddpfPixelFormat, &pTMObj->pixel ); /*===================================================================*/ /* Fill the texture using the PixelInfo structure to do the mapping. */ /*===================================================================*/ UpdateTexture( pTMObj, FALSE, NULL, (UCHAR *)pPixels ); /*=======================*/ /* Create VIDEO surface. */ /*=======================*/ rc = LoadTextureInVideo( pHAL, pTMObj ); if ( rc == FALSE ) return FALSE; /* Make this the current texture. */ rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 ); if ( FAILED(rc) ) { DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) )); pHAL->lpD3DDevice->SetTexture( 0, NULL ); return FALSE; } return TRUE; } /*===========================================================================*/ /* This function will handle the creation and destruction of the texture */ /* surfaces on the card. Using the dw'V'Width/Height dimensions the call */ /* try and create the texture on the card and keep using FreeTextureMemory */ /* until the surace can be created. Once the surface is created we get the */ /* interface that we will use to make it the current texture. I didn't put */ /* the code to make the texture current in this function as BIND needs to */ /* use the same code and this function doesn't always get called when we do a*/ /* bind. */ /*===========================================================================*/ /* RETURN: TRUE, FALSE. */ /*===========================================================================*/ static BOOL LoadTextureInVideo( PMESAD3DHAL pHAL, PTM_OBJECT pTMObj ) { DDSURFACEDESC2 ddsd2; HRESULT rc; DPF(( DBG_FUNC, "LoadTextureInVideo();" )); /* Kill the interface if we have one no matter what. */ if ( pTMObj->lpD3DTexture2 ) { DPF(( DBG_TXT_INFO, "Release Texture2" )); pTMObj->lpD3DTexture2->Release(); pTMObj->lpD3DTexture2 = NULL; } /* Kill the Video surface. TODO: need some reuse system... */ if ( pTMObj->lpDDS_Video ) { DPF(( DBG_TXT_INFO, "Release texture (VID)" )); DX_RESTORE( pTMObj->lpDDS_Video ); pTMObj->lpDDS_Video->Release(); pTMObj->lpDDS_Video = NULL; } /* Request a surface in Video memory. */ memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) ); ddsd2.dwSize = sizeof( DDSURFACEDESC2 ); ddsd2.dwWidth = pTMObj->dwVWidth; ddsd2.dwHeight = pTMObj->dwVHeight; ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; ddsd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY; ddsd2.ddsCaps.dwCaps2 = 0L; memset( &ddsd2.ddpfPixelFormat, 0, sizeof(DDPIXELFORMAT) ); ddsd2.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT ); ddsd2.ddpfPixelFormat.dwFlags = pTMObj->dwFlags; rc = pHAL->lpD3DDevice->EnumTextureFormats( EnumPFHook, &ddsd2.ddpfPixelFormat ); if ( FAILED(rc) ) { RIP( pHAL, "EnumerTextureFormats ->", ErrorStringD3D(rc) ); return FALSE; } /* Make sure we lock so we don't nuke this texture trying to free memory for it. */ pTMObj->bLock = TRUE; /* Start a loop that will free all textures until we have created the texture */ /* surface or we can't free up more memory. */ do { /* Try to create the texture surface. */ rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pTMObj->lpDDS_Video, NULL ); if ( !FAILED(rc) ) break; DPF(( DBG_TXT_INFO, "Free Texture Memory" )); /* DestroyTexture will return TRUE if a surface was freed. */ } while( FreeTextureMemory(pHAL,NULL) ); /* Make sure we unlock or we won't be able to nuke the TMO later. */ pTMObj->bLock = FALSE; /* Did we create a valid texture surface? */ if ( FAILED(rc) ) { DPF(( DBG_TXT_WARN, "Failed to load texture" )); pHAL->lpD3DDevice->SetTexture( 0, NULL ); return FALSE; } DX_RESTORE( pTMObj->lpDDS_System ); DX_RESTORE( pTMObj->lpDDS_Video ); DPF(( DBG_TXT_INFO, "Texture Blt SYSTEM -> VID" )); /* Now blt the texture in system memory to the card. */ rc = pTMObj->lpDDS_Video->Blt( NULL, pTMObj->lpDDS_System, NULL, DDBLT_WAIT, NULL ); if ( FAILED(rc) ) { RIP( pHAL, "Blt (TEXTURE) ->", ErrorStringD3D(rc) ); return FALSE; } /* Get the Texture interface that is used to render with. */ pTMObj->lpDDS_Video->QueryInterface( IID_IDirect3DTexture2, (void **)&pTMObj->lpD3DTexture2 ); if ( pTMObj->lpD3DTexture2 == NULL ) { DPF(( DBG_TXT_WARN, "Failed QueryTextureInterface" )); pHAL->lpD3DDevice->SetTexture( 0, NULL ); return FALSE; } return TRUE; } /*===========================================================================*/ /* If this function gets a texture object struc then we will try and free */ /* it. If we get a NULL then we will search from the bottom up and free one */ /* VMEM surface. I can only free when the surface isn't locked and of course*/ /* there must be a VMEM surface. We never free SMEM surfaces as that isn't */ /* the point. */ /* TODO: should have a pointer to the bottom of the stack really. */ /*===========================================================================*/ /* RETURN: */ /*===========================================================================*/ static BOOL FreeTextureMemory( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject ) { PTM_OBJECT pCurrent; BOOL bFreed = FALSE; DPF(( DBG_FUNC, "FreeTextureMemory();" )); DPF(( DBG_TXT_WARN, "FREE TEXTURE!" )); /* Just to be safe. */ if ( !pHAL || !pHAL->pTMList ) { DPF(( DBG_TXT_WARN, "FreeTextureMemory() -> NULL pHAL/pHAL->pTMList" )); return FALSE; } /* Free the last texture in the list. */ if ( pTMObject == NULL ) { DPF(( DBG_TXT_INFO, "Free Last texture in cache" )); /* Find the last texture object. */ for( pCurrent = pHAL->pTMList; pCurrent->next; pCurrent = pCurrent->next ); /* Now backup until we find a texture on the card. */ while( pCurrent && (pCurrent->lpDDS_Video == NULL) && (pCurrent->bLock == FALSE) ) pCurrent = pCurrent->prev; /* Didn't find anything. */ if ( pCurrent == NULL ) { DPF(( DBG_TXT_INFO, "No texture memory freed" )); return FALSE; } } else { /* See if we can find this texture object. */ for( pCurrent = pHAL->pTMList; pCurrent && (pCurrent != pTMObject); pCurrent = pCurrent->next ); /* Didn't find anything. */ if ( pCurrent == NULL ) { DPF(( DBG_TXT_INFO, "Requested texture to be freed NOT FOUND" )); return FALSE; } } /* Can't free this baby. */ if ( pCurrent->bLock == TRUE ) { DPF(( DBG_TXT_WARN, "Requested texture LOCKED" )); return FALSE; } /* Free the texture memory. */ if ( pCurrent->lpD3DTexture2 ) { DPF(( DBG_TXT_INFO, "Release Texture2" )); pCurrent->lpD3DTexture2->Release(); pCurrent->lpD3DTexture2 = NULL; bFreed = TRUE; } if ( pCurrent->lpDDS_Video ) { DPF(( DBG_TXT_INFO, "Release texture (VID):" )); DPF(( DBG_TXT_INFO, "dwName: %d", pCurrent->dwName )); DPF(( DBG_TXT_INFO, "cx: %d, cy: %d", pCurrent->dwVWidth, pCurrent->dwVHeight )); pCurrent->lpDDS_Video->Release(); pCurrent->lpDDS_Video = NULL; bFreed = TRUE; } return bFreed; } /*===========================================================================*/ /* This function searches the linked list of texture objects in the supplied*/ /* D3Dwrapper structure. If it finds a match it will free it and pull it out*/ /* of the linked list. The function works on the bases of a matching pointer*/ /* to the object (not matching content). */ /* If the function gets passed a NULL then we want to free the last texture */ /* object in the list. Used in a loop to destory all. */ /*===========================================================================*/ /* RETURN: TRUE, FALSE. */ /*===========================================================================*/ static BOOL DestroyTextureObject( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject ) { PTM_OBJECT pCurrent; DPF(( DBG_FUNC, "DestoryTextureObject();" )); /* Just to be safe. */ if ( !pHAL || !pHAL->pTMList ) { DPF(( DBG_TXT_WARN, "DestroyTextureObject() -> NULL pHAL/pHAL->pTMList" )); return FALSE; } /* Free the last texture in the list. */ if ( pTMObject == NULL ) { /* Find the last texture object. */ for( pCurrent = pHAL->pTMList; pCurrent->next; pCurrent = pCurrent->next ); } else { /* See if we can find this texture object. */ for( pCurrent = pHAL->pTMList; pCurrent && (pCurrent != pTMObject); pCurrent = pCurrent->next ); /* Didn't find anything. */ if ( pCurrent == NULL ) { DPF(( DBG_TXT_WARN, "No textures to be freed" )); return FALSE; } } /* Can't free this baby. */ if ( pCurrent->bLock == TRUE ) { DPF(( DBG_TXT_WARN, "Requested texture to be freed LOCKED" )); return FALSE; } /* Free the texture memory. */ if ( pCurrent->lpD3DTexture2 ) { DPF(( DBG_TXT_INFO, "Release Texture2" )); pCurrent->lpD3DTexture2->Release(); pCurrent->lpD3DTexture2 = NULL; } if ( pCurrent->lpDDS_Video ) { DPF(( DBG_TXT_INFO, "Release texture (VID):" )); pCurrent->lpDDS_Video->Release(); pCurrent->lpDDS_Video = NULL; } if ( pCurrent->lpDDS_System ) { DPF(( DBG_TXT_INFO, "Release texture (SYS):" )); pCurrent->lpDDS_System->Release(); pCurrent->lpDDS_System = NULL; } /* Pull this texture out of the list. */ if ( pCurrent == pHAL->pTMList ) pHAL->pTMList = NULL; if ( pCurrent->prev ) (pCurrent->prev)->next = pCurrent->next; if ( pCurrent->next ) (pCurrent->next)->prev = pCurrent->prev; FREE( pCurrent ); return TRUE; } /*===========================================================================*/ /* This function is the callback function that gets called when we are doing*/ /* an enumeration of the texture formats supported by this device. The choice*/ /* is made by checking to see if we have a match with the supplied D3D pixel-*/ /* format. So the enumeration has to pass a desired D3D PF as the user var. */ /*===========================================================================*/ /* RETURN: D3DENUMRET_OK, D3DENUMRET_CANCEL. */ /*===========================================================================*/ static void UpdateTexture( PTM_OBJECT pTMObj, BOOL bVideo, RECT *pRect, UCHAR *pixels ) { LPDIRECTDRAWSURFACE4 lpDDS; DDSURFACEDESC2 ddsd2; DWORD srcPitch, dwHeight, dwWidth, dwCol, dwColor; UCHAR *pSrc, *pSrcRow, *pDest, *pDestRow; int rc; // TODO: Do I need to pass the h/w when its in the object! DPF(( DBG_FUNC, "UpdateTexture();" )); /* Get the surface pointer we are looking for. */ lpDDS = (bVideo) ? pTMObj->lpDDS_Video : pTMObj->lpDDS_System; /*===================================================================*/ /* Fill the texture using the PixelInfo structure to do the mapping. */ /*===================================================================*/ /* Get the surface pointer. */ memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) ); ddsd2.dwSize = sizeof(DDSURFACEDESC2); rc = lpDDS->Lock( NULL, &ddsd2, DDLOCK_WAIT, NULL ); if ( FAILED(rc) ) { RIP( NULL, "Lock (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) ); return; } /* For now we are only updating the system surface so use its dimensions. */ dwWidth = (bVideo) ? pTMObj->dwVWidth : pTMObj->dwSWidth; dwHeight = (bVideo) ? pTMObj->dwVHeight : pTMObj->dwSHeight; /* If we are updating the whole surface then the pDest/pSrc will */ /* always be the same. */ if ( pRect == NULL ) { pDest = (UCHAR *)ddsd2.lpSurface; pSrc = pixels; } /* Fill the texture surface based on the pixelformat flags. */ if ( pTMObj->dwFlags == (DDPF_RGB | DDPF_ALPHAPIXELS) ) { srcPitch = dwWidth * 4; if ( pRect ) { pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb); pSrc = pixels + (pRect->top * dwWidth * 4) + (pRect->left * 4); dwHeight = (pRect->bottom - pRect->top); dwWidth = (pRect->right - pRect->left); } for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch ) { for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ ) { dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift ); dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.gScale)) << pTMObj->pixel.gShift ); dwColor |= ( ((DWORD)(*(pSrc+2) * pTMObj->pixel.bScale)) << pTMObj->pixel.bShift ); if ( pTMObj->pixel.aScale == -1.0 ) dwColor |= ( (*(pSrc+3) & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 ); else dwColor |= ( ((DWORD)(*(pSrc+3) * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift ); memcpy( pDest, &dwColor, pTMObj->pixel.cb ); pDest += pTMObj->pixel.cb; pSrc += 4; } } } else if ( pTMObj->dwFlags == DDPF_RGB ) { srcPitch = dwWidth * 3; if ( pRect ) { pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb); pSrc = pixels + (pRect->top * dwWidth * 3) + (pRect->left * 3); dwHeight = (pRect->bottom - pRect->top); dwWidth = (pRect->right - pRect->left); } for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch ) { for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ ) { dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift ); dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.gScale)) << pTMObj->pixel.gShift ); dwColor |= ( ((DWORD)(*(pSrc+2) * pTMObj->pixel.bScale)) << pTMObj->pixel.bShift ); memcpy( pDest, &dwColor, pTMObj->pixel.cb ); pDest += pTMObj->pixel.cb; pSrc += 3; } } } else if ( pTMObj->dwFlags == (DDPF_LUMINANCE | DDPF_ALPHAPIXELS) ) { srcPitch = dwWidth * 2; if ( pRect ) { pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb); pSrc = pixels + (pRect->top * dwWidth * 2) + (pRect->left * 2); dwHeight = (pRect->bottom - pRect->top); dwWidth = (pRect->right - pRect->left); } for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch ) { for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ ) { dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift ); if ( pTMObj->pixel.aScale == -1.0 ) dwColor |= ( (*(pSrc+1) & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 ); else dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift ); memcpy( pDest, &dwColor, pTMObj->pixel.cb ); pDest += pTMObj->pixel.cb; pSrc += 2; } } } else if ( pTMObj->dwFlags == DDPF_LUMINANCE ) { srcPitch = dwWidth; if ( pRect ) { pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb); pSrc = pixels + (pRect->top * dwWidth) + (pRect->left); dwHeight = (pRect->bottom - pRect->top); dwWidth = (pRect->right - pRect->left); } for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch ) { for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ ) { dwColor = ( ((DWORD)(*pSrc * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift ); memcpy( pDest, &dwColor, pTMObj->pixel.cb ); pDest += pTMObj->pixel.cb; pSrc++; } } } else if ( pTMObj->dwFlags == DDPF_ALPHAPIXELS ) { srcPitch = dwWidth; if ( pRect ) { pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb); pSrc = pixels + (pRect->top * dwWidth) + (pRect->left); dwHeight = (pRect->bottom - pRect->top); dwWidth = (pRect->right - pRect->left); } for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch ) { for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ ) { if ( pTMObj->pixel.aScale == -1.0 ) dwColor = ( (*pSrc & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 ); else dwColor = ( ((DWORD)(*pSrc * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift ); memcpy( pDest, &dwColor, pTMObj->pixel.cb ); pDest += pTMObj->pixel.cb; pSrc++; } } } /* Unlock the surface. */ rc = lpDDS->Unlock( NULL ); if ( FAILED(rc) ) { RIP( NULL, "Unlock (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) ); } } /*===========================================================================*/ /* This function is the callback function that gets called when we are doing*/ /* an enumeration of the texture formats supported by this device. The choice*/ /* is made by checking to see if we have a match with the supplied D3D pixel-*/ /* format. So the enumeration has to pass a desired D3D PF as the user var. */ /*===========================================================================*/ /* RETURN: D3DENUMRET_OK, D3DENUMRET_CANCEL. */ /*===========================================================================*/ HRESULT CALLBACK EnumPFHook( LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext ) { LPDDPIXELFORMAT lpDDPixFmtRequest = (LPDDPIXELFORMAT)lpContext; PIXELINFO pixel; DPF(( DBG_FUNC, "EnumPFHook();" )); if ( lpDDPixFmt->dwFlags == lpDDPixFmtRequest->dwFlags ) { /* Are we looking for an alpha channel? */ if ( lpDDPixFmtRequest->dwFlags & DDPF_ALPHAPIXELS ) { /* Try for something that has more then 1bits of Alpha. */ Solve8BitChannelPixelFormat( lpDDPixFmt, &pixel ); if ( pixel.aScale == -1.0 ) { /* Save this format no matter what as its a match of sorts. */ memcpy( lpDDPixFmtRequest, lpDDPixFmt, sizeof(DDPIXELFORMAT) ); return D3DENUMRET_OK; } } /* Save this format as its a good match. */ memcpy( lpDDPixFmtRequest, lpDDPixFmt, sizeof(DDPIXELFORMAT) ); /* We are happy at this point so lets leave. */ return D3DENUMRET_CANCEL; } return D3DENUMRET_OK; }