Implement UpdateTexture and UpdateSurface in wined3d.
Allow NULL members of WINED3DSURFACE_DESC to be set to Surface_GetDesc
so that the whole structure doesn't have to be filled just to get back
one value.

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 9990ab9..5734f21 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4618,10 +4618,52 @@
     return D3D_OK;
 }
 
+ /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
 HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture,  IWineD3DBaseTexture *pDestinationTexture){
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    
-    TRACE("(%p) : stub\n", This);
+    D3DRESOURCETYPE sourceType;
+    D3DRESOURCETYPE destinationType;
+    IWineD3DTextureImpl *pDestTexture = (IWineD3DTextureImpl *)pDestinationTexture;
+    IWineD3DTextureImpl *pSrcTexture  = (IWineD3DTextureImpl *)pSourceTexture;
+    int i;
+
+    sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
+    destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
+    if(sourceType != D3DRTYPE_TEXTURE && destinationType != D3DRTYPE_TEXTURE){
+        FIXME("(%p) Only D3DRTYPE_TEXTURE to D3DRTYPE_TEXTURE supported\n", This);
+        return D3DERR_INVALIDCALL;
+    }
+    TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
+
+    /** TODO: Get rid of the casts to IWineD3DBaseTextureImpl
+        repalce surfaces[x] with GetSurfaceLevel, or GetCubeMapSurface etc..
+        think about moving the code into texture, and adding a member to base texture to occomplish this **/
+
+    /* Make sure that the destination texture is loaded */
+    IWineD3DBaseTexture_PreLoad(pDestinationTexture);
+    TRACE("Loading source texture\n");
+
+    if(pSrcTexture->surfaces[0] == NULL || pDestTexture->surfaces[0] == NULL){
+        FIXME("(%p) Texture src %p or dest %p has not surface %p %p\n", This, pSrcTexture, pDestTexture,
+               pSrcTexture->surfaces[0], pDestTexture->surfaces[0]);
+    }
+
+    if(((IWineD3DSurfaceImpl *)pSrcTexture->surfaces[0])->resource.pool != D3DPOOL_SYSTEMMEM ||
+        ((IWineD3DSurfaceImpl *)pDestTexture->surfaces[0])->resource.pool != D3DPOOL_DEFAULT){
+
+        FIXME("(%p) source %p must be SYSTEMMEM and dest %p must be DEFAULT\n",This, pSrcTexture, pDestTexture);
+        return D3DERR_INVALIDCALL;
+    }
+    /** TODO: check that both textures have the same number of levels  **/
+#if 0
+    if(IWineD3DBaseTexture_GetLevelCount(pDestinationTexture)  !=IWineD3DBaseTexture_GetLevelCount(pSourceTexture))
+            return D3DERR_INVALIDCALL;
+#endif
+    /** TODO: move this code into baseTexture? device should never touch impl*'s **/
+    for(i = 0 ; i < IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) ; i++){
+        IWineD3DDevice_UpdateSurface(iface, pSrcTexture->surfaces[i], NULL, pDestTexture->surfaces[i], NULL);
+    }
+
     return D3D_OK;
 }
 
@@ -4731,10 +4773,169 @@
 
 
 HRESULT  WINAPI  IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
-    IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
-    FIXME("(%p) : stub\n", This);
-    return D3D_OK;
+    IWineD3DDeviceImpl  *This         = (IWineD3DDeviceImpl *) iface;
+    /** TODO: remove casts to IWineD3DSurfaceImpl
+     *       NOTE: move code to surface to accomplish this
+      ****************************************/
+    IWineD3DSurfaceImpl *pSrcSurface  = (IWineD3DSurfaceImpl *)pSourceSurface;
+    int srcWidth, srcHeight, srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
+    WINED3DFORMAT destFormat, srcFormat;
+    UINT destSize;
+    int destLeft, destTop;
+    D3DPOOL     srcPool, destPool;
+    int offset    = 0;
+    int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
+    glDescriptor *glDescription = NULL;
+    GLenum textureDimensions = GL_TEXTURE_2D;
+    IWineD3DBaseTexture *baseTexture;
 
+    WINED3DSURFACE_DESC  winedesc;
+
+    memset(&winedesc, 0, sizeof(winedesc));
+    winedesc.Width  = &srcSurfaceWidth;
+    winedesc.Height = &srcSurfaceHeight;
+    winedesc.Pool   = &srcPool;
+    winedesc.Format = &srcFormat;
+
+    IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
+
+    winedesc.Width  = &destSurfaceWidth;
+    winedesc.Height = &destSurfaceHeight;
+    winedesc.Pool   = &destPool;
+    winedesc.Format = &destFormat;
+    winedesc.Size   = &destSize;
+
+    IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
+
+    if(srcPool != D3DPOOL_SYSTEMMEM  || destPool != D3DPOOL_DEFAULT){
+        FIXME("source %p must be SYSTEMMEM and dest %p must be DEFAULT\n", pSourceSurface, pDestinationSurface);
+        return D3DERR_INVALIDCALL;
+    }
+    /* TODO:  change this to use bindTexture */
+    /* Make sure the surface is loaded and upto date */
+    IWineD3DSurface_PreLoad(pDestinationSurface);
+
+    IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
+
+    ENTER_GL();
+
+    /* this needs to be done in lines if the sourceRect != the sourceWidth */
+    srcWidth   = pSourceRect ? pSourceRect->right - pSourceRect->left   : srcSurfaceWidth;
+    srcHeight  = pSourceRect ? pSourceRect->top   - pSourceRect->bottom : srcSurfaceHeight;
+    destLeft   = pDestPoint  ? pDestPoint->x : 0;
+    destTop    = pDestPoint  ? pDestPoint->y : 0;
+
+
+    /* This function doesn't support compressed textures
+    the pitch is just bytesPerPixel * width */
+
+    if(srcWidth != srcSurfaceWidth  || (pSourceRect != NULL && pSourceRect->left != 0) ){
+        rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
+        offset   += pSourceRect->left * pSrcSurface->bytesPerPixel;
+        /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
+    }
+    /* TODO DXT formats */
+
+    if(pSourceRect != NULL && pSourceRect->top != 0){
+       offset +=  pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
+    }
+    TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
+    ,This
+    ,glDescription->level
+    ,destLeft
+    ,destTop
+    ,srcWidth
+    ,srcHeight
+    ,glDescription->glFormat
+    ,glDescription->glType
+    ,IWineD3DSurface_GetData(pSourceSurface)
+    );
+
+    /* Sanity check */
+    if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
+    /* need to lock the surface to get the data */
+       FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
+    }
+    /* TODO: Cube and volume support */
+    if(rowoffset != 0){
+        /* not a whole row so we have to do it a line at a time */
+        int j;
+        /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
+        unsigned char* data =((unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
+
+        for(j = destTop ; j < (srcHeight + destTop) ; j++){
+
+                glTexSubImage2D(glDescription->target
+                    ,glDescription->level
+                    ,destLeft
+                    ,j
+                    ,srcWidth
+                    ,1
+                    ,glDescription->glFormat
+                    ,glDescription->glType
+                    ,data/* could be quicker using */
+                );
+            data += rowoffset;
+        }
+
+    } else { /* Full width, so just write out the whole texture */
+
+        if (WINED3DFMT_DXT1 == destFormat ||
+            WINED3DFMT_DXT3 == destFormat ||
+            WINED3DFMT_DXT5 == destFormat) {
+            if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
+                if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
+                    /* FIXME: The easy way to do this is lock the destination, and copy the bits accross */
+                    FIXME("Updating part of a compressed texture is not supported at the moment\n");
+                } if (destFormat != srcFormat) {
+                    FIXME("Updating mixed format compressed texture is not curretly support\n");
+                } else {
+                    GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
+                                                        glDescription->level,
+                                                        glDescription->glFormatInternal,
+                                                        srcWidth,
+                                                        srcHeight,
+                                                        0,
+                                                        destSize,
+                                                        IWineD3DSurface_GetData(pSourceSurface));
+                }
+            } else {
+                FIXME("Attempting to update a DXT compressed texture without hardware support\n");
+            }
+
+
+        } else {
+            /* some applications can not handle odd pitches returned by soft non-power2, so we have
+               to repack the data from pow2Width/Height to expected Width,Height, this makes the
+               data returned by GetData non-power2 width/height with hardware non-power2
+               pow2Width/height are set to surface width height, repacking isn't needed so it
+               doesn't matter which function gets called. */
+            glTexSubImage2D(glDescription->target
+                    ,glDescription->level
+                    ,destLeft
+                    ,destTop
+                    ,srcWidth
+                    ,srcHeight
+                    ,glDescription->glFormat
+                    ,glDescription->glType
+                    ,IWineD3DSurface_GetData(pSourceSurface)
+                );
+
+        }
+     }
+    checkGLcall("glTexSubImage2D");
+    /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
+     * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
+     * surface bigger than it needs to be hmm.. */
+    if (D3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
+        textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
+        IWineD3DBaseTexture_Release(baseTexture);
+    }
+
+    glDisable(textureDimensions); /* This needs to be managed better.... */
+    LEAVE_GL();
+
+    return D3D_OK;
 }
 
 /* Implementation details at http://developer.nvidia.com/attach/6494
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 988893c..483f05b 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -1741,11 +1741,12 @@
     /* And re-upload any dirty textures */
     for (i=0; i<GL_LIMITS(textures); i++) {
 
-        if ((This->stateBlock->textures[i] != NULL) && 
-            (IWineD3DBaseTexture_GetDirty(This->stateBlock->textures[i])))
-        {
-            /* Load up the texture now */
-            IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
+        if (This->stateBlock->textures[i] != NULL) {
+	
+            if (IWineD3DBaseTexture_GetDirty(This->stateBlock->textures[i])) {
+                /* Load up the texture now */
+                IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
+            }
             if (IWineD3DResourceImpl_GetType((IWineD3DResource *)This->stateBlock->textures[i]) == D3DRTYPE_TEXTURE ) {
                 /* TODO: Is this right, as its cast all texture types to texture8... checkme */
                 IWineD3DSurface *surface;
@@ -1753,8 +1754,8 @@
                 if (((IWineD3DSurfaceImpl *)surface)->nonpow2) {
                     nonPower2 = TRUE;
                 }
-            }
-        }
+	    }
+        } 
     }
 
     /* Now draw the graphics to the screen */
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 425eb65..af25320 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -190,15 +190,15 @@
     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
 
     TRACE("(%p) : copying into %p\n", This, pDesc);
-    *(pDesc->Format)             = This->resource.format;
-    *(pDesc->Type)               = This->resource.resourceType;
-    *(pDesc->Usage)              = This->resource.usage;
-    *(pDesc->Pool)               = This->resource.pool;
-    *(pDesc->Size)               = This->resource.size;   /* dx8 only */
-    *(pDesc->MultiSampleType)    = This->currentDesc.MultiSampleType;
-    *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
-    *(pDesc->Width)              = This->currentDesc.Width;
-    *(pDesc->Height)             = This->currentDesc.Height;
+    if(pDesc->Format != NULL)             *(pDesc->Format) = This->resource.format;
+    if(pDesc->Type != NULL)               *(pDesc->Type)   = This->resource.resourceType;
+    if(pDesc->Usage != NULL)              *(pDesc->Usage)              = This->resource.usage;
+    if(pDesc->Pool != NULL)               *(pDesc->Pool)               = This->resource.pool;
+    if(pDesc->Size != NULL)               *(pDesc->Size)               = This->resource.size;   /* dx8 only */
+    if(pDesc->MultiSampleType != NULL)    *(pDesc->MultiSampleType)    = This->currentDesc.MultiSampleType;
+    if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
+    if(pDesc->Width != NULL)              *(pDesc->Width)              = This->currentDesc.Width;
+    if(pDesc->Height != NULL)             *(pDesc->Height)             = This->currentDesc.Height;
     return D3D_OK;
 }
 
@@ -406,8 +406,6 @@
             *****************************************/
         if (!notInContext) { /* Only read the buffer if it's in the current context */
             long j;
-            GLenum format = D3DFmt2GLFmt(myDevice, This->resource.format);
-            GLenum type   = D3DFmt2GLType(myDevice, This->resource.format);
 #if 0
             /* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time,
             *  This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
@@ -422,16 +420,16 @@
                     glReadPixels(0, 0,
                     This->currentDesc.Width,
                     This->currentDesc.Height,
-                    format,
-                    type,
+                    This->glDescription.glFormat,
+                    This->glDescription.glType,
                     (char *)pLockedRect->pBits);
             }else if (This->lockedRect.left ==0 &&  This->lockedRect.right == This->currentDesc.Width) {
                     glReadPixels(0,
                     This->lockedRect.top,
                     This->currentDesc.Width,
                     This->currentDesc.Height,
-                    format,
-                    type,
+                    This->glDescription.glFormat,
+                    This->glDescription.glType,
                     (char *)pLockedRect->pBits);
             } else{
 
@@ -440,8 +438,8 @@
                                  This->lockedRect.bottom - j - 1, 
                                  This->lockedRect.right - This->lockedRect.left, 
                                  1,
-                                 format, 
-                                 type, 
+                                 This->glDescription.glFormat,
+                                 This->glDescription.glType,
                                  (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
 
                 }
@@ -873,8 +871,8 @@
                          This->pow2Width,
                          This->pow2Height,
                          0/*border*/,
-                         D3DFmt2GLFmt(This->resource.wineD3DDevice, This->resource.format),
-                         D3DFmt2GLType(This->resource.wineD3DDevice, This->resource.format),
+                         This->glDescription.glFormat,
+                         This->glDescription.glType,
                          NULL);
 
             checkGLcall("glTexImage2D");