[D3DRM]
authorAmine Khaldi <amine.khaldi@reactos.org>
Mon, 29 Sep 2014 17:24:32 +0000 (17:24 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Mon, 29 Sep 2014 17:24:32 +0000 (17:24 +0000)
* Import from Wine 1.7.27.
CORE-8082 #resolve #comment Imported in r64396. Thanks!
CORE-8540

svn path=/trunk/; revision=64398

17 files changed:
reactos/dll/directx/wine/CMakeLists.txt
reactos/dll/directx/wine/d3drm/CMakeLists.txt [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/d3drm.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/d3drm.spec [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/d3drm_main.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/d3drm_private.h [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/device.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/face.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/frame.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/light.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/material.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/math.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/meshbuilder.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/texture.c [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/version.rc [new file with mode: 0644]
reactos/dll/directx/wine/d3drm/viewport.c [new file with mode: 0644]
reactos/media/doc/README.WINE

index a58fb6a..e62d321 100644 (file)
@@ -3,6 +3,7 @@ add_subdirectory(amstream)
 add_subdirectory(d3d8)
 add_subdirectory(d3d9)
 add_subdirectory(d3dcompiler_43)
+add_subdirectory(d3drm)
 add_subdirectory(d3dx9_24)
 add_subdirectory(d3dx9_25)
 add_subdirectory(d3dx9_26)
diff --git a/reactos/dll/directx/wine/d3drm/CMakeLists.txt b/reactos/dll/directx/wine/d3drm/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bc3bc9f
--- /dev/null
@@ -0,0 +1,35 @@
+
+add_definitions(-D__WINESRC__)
+include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine)
+spec2def(d3drm.dll d3drm.spec)
+
+list(APPEND SOURCE
+    d3drm.c
+    d3drm_main.c
+    device.c
+    face.c
+    frame.c
+    light.c
+    material.c
+    math.c
+    meshbuilder.c
+    texture.c
+    viewport.c
+    d3drm_private.h)
+
+add_library(d3drm SHARED
+    ${SOURCE}
+    version.rc
+    ${CMAKE_CURRENT_BINARY_DIR}/d3drm_stubs.c
+    ${CMAKE_CURRENT_BINARY_DIR}/d3drm.def)
+
+set_module_type(d3drm win32dll UNICODE)
+target_link_libraries(d3drm dxguid uuid wine)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+    target_link_libraries(d3drm mingwex)
+endif()
+
+add_importlibs(d3drm d3dxof msvcrt kernel32 ntdll)
+add_pch(d3drm d3drm_private.h SOURCE)
+add_cd_file(TARGET d3drm DESTINATION reactos/system32 FOR all)
diff --git a/reactos/dll/directx/wine/d3drm/d3drm.c b/reactos/dll/directx/wine/d3drm/d3drm.c
new file mode 100644 (file)
index 0000000..b1d2e69
--- /dev/null
@@ -0,0 +1,1489 @@
+/*
+ * Implementation of IDirect3DRM Interface
+ *
+ * Copyright 2010, 2012 Christian Costa
+ * Copyright 2011 André Hentschel
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+static const char* get_IID_string(const GUID* guid)
+{
+    if (IsEqualGUID(guid, &IID_IDirect3DRMFrame))
+        return "IID_IDirect3DRMFrame";
+    else if (IsEqualGUID(guid, &IID_IDirect3DRMFrame2))
+        return "IID_IDirect3DRMFrame2";
+    else if (IsEqualGUID(guid, &IID_IDirect3DRMFrame3))
+        return "IID_IDirect3DRMFrame3";
+    else if (IsEqualGUID(guid, &IID_IDirect3DRMMeshBuilder))
+        return "IID_IDirect3DRMMeshBuilder";
+    else if (IsEqualGUID(guid, &IID_IDirect3DRMMeshBuilder2))
+        return "IID_IDirect3DRMMeshBuilder2";
+    else if (IsEqualGUID(guid, &IID_IDirect3DRMMeshBuilder3))
+        return "IID_IDirect3DRMMeshBuilder3";
+
+    return "?";
+}
+
+struct d3drm
+{
+    IDirect3DRM IDirect3DRM_iface;
+    IDirect3DRM2 IDirect3DRM2_iface;
+    IDirect3DRM3 IDirect3DRM3_iface;
+    LONG ref;
+};
+
+static inline struct d3drm *impl_from_IDirect3DRM(IDirect3DRM *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm, IDirect3DRM_iface);
+}
+
+static inline struct d3drm *impl_from_IDirect3DRM2(IDirect3DRM2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm, IDirect3DRM2_iface);
+}
+
+static inline struct d3drm *impl_from_IDirect3DRM3(IDirect3DRM3 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm, IDirect3DRM3_iface);
+}
+
+static HRESULT WINAPI d3drm1_QueryInterface(IDirect3DRM *iface, REFIID riid, void **out)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRM)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *out = &d3drm->IDirect3DRM_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRM2))
+    {
+        *out = &d3drm->IDirect3DRM2_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRM3))
+    {
+        *out = &d3drm->IDirect3DRM3_iface;
+    }
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI d3drm1_AddRef(IDirect3DRM *iface)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM(iface);
+    ULONG refcount = InterlockedIncrement(&d3drm->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm1_Release(IDirect3DRM *iface)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM(iface);
+    ULONG refcount = InterlockedDecrement(&d3drm->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+        HeapFree(GetProcessHeap(), 0, d3drm);
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm1_CreateObject(IDirect3DRM *iface,
+        REFCLSID clsid, IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, clsid %s, outer %p, iid %s, out %p stub!\n",
+            iface, debugstr_guid(clsid), outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_CreateFrame(IDirect3DRM *iface,
+        IDirect3DRMFrame *parent_frame, IDirect3DRMFrame **frame)
+{
+    TRACE("iface %p, parent_frame %p, frame %p.\n", iface, parent_frame, frame);
+
+    return Direct3DRMFrame_create(&IID_IDirect3DRMFrame, (IUnknown *)parent_frame, (IUnknown **)frame);
+}
+
+static HRESULT WINAPI d3drm1_CreateMesh(IDirect3DRM *iface, IDirect3DRMMesh **mesh)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM(iface);
+
+    TRACE("iface %p, mesh %p.\n", iface, mesh);
+
+    return IDirect3DRM3_CreateMesh(&d3drm->IDirect3DRM3_iface, mesh);
+}
+
+static HRESULT WINAPI d3drm1_CreateMeshBuilder(IDirect3DRM *iface, IDirect3DRMMeshBuilder **mesh_builder)
+{
+    TRACE("iface %p, mesh_builder %p.\n", iface, mesh_builder);
+
+    return Direct3DRMMeshBuilder_create(&IID_IDirect3DRMMeshBuilder, (IUnknown **)mesh_builder);
+}
+
+static HRESULT WINAPI d3drm1_CreateFace(IDirect3DRM *iface, IDirect3DRMFace **face)
+{
+    TRACE("iface %p, face %p.\n", iface, face);
+
+    return Direct3DRMFace_create(&IID_IDirect3DRMFace, (IUnknown **)face);
+}
+
+static HRESULT WINAPI d3drm1_CreateAnimation(IDirect3DRM *iface, IDirect3DRMAnimation **animation)
+{
+    FIXME("iface %p, animation %p stub!\n", iface, animation);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_CreateAnimationSet(IDirect3DRM *iface, IDirect3DRMAnimationSet **set)
+{
+    FIXME("iface %p, set %p stub!\n", iface, set);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_CreateTexture(IDirect3DRM *iface,
+        D3DRMIMAGE *image, IDirect3DRMTexture **texture)
+{
+    FIXME("iface %p, image %p, texture %p partial stub.\n", iface, image, texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm1_CreateLight(IDirect3DRM *iface,
+        D3DRMLIGHTTYPE type, D3DCOLOR color, IDirect3DRMLight **light)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM(iface);
+
+    TRACE("iface %p, type %#x, color 0x%08x, light %p.\n", iface, type, color, light);
+
+    return IDirect3DRM3_CreateLight(&d3drm->IDirect3DRM3_iface, type, color, light);
+}
+
+static HRESULT WINAPI d3drm1_CreateLightRGB(IDirect3DRM *iface, D3DRMLIGHTTYPE type,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue, IDirect3DRMLight **light)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM(iface);
+
+    TRACE("iface %p, type %#x, red %.8e, green %.8e, blue %.8e, light %p.\n",
+            iface, type, red, green, blue, light);
+
+    return IDirect3DRM3_CreateLightRGB(&d3drm->IDirect3DRM3_iface, type, red, green, blue, light);
+}
+
+static HRESULT WINAPI d3drm1_CreateMaterial(IDirect3DRM *iface,
+        D3DVALUE power, IDirect3DRMMaterial **material)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM(iface);
+
+    TRACE("iface %p, power %.8e, material %p.\n", iface, power, material);
+
+    return IDirect3DRM3_CreateMaterial(&d3drm->IDirect3DRM3_iface, power, (IDirect3DRMMaterial2 **)material);
+}
+
+static HRESULT WINAPI d3drm1_CreateDevice(IDirect3DRM *iface,
+        DWORD width, DWORD height, IDirect3DRMDevice **device)
+{
+    FIXME("iface %p, width %u, height %u, device %p partial stub!\n", iface, width, height, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm1_CreateDeviceFromSurface(IDirect3DRM *iface, GUID *guid,
+        IDirectDraw *ddraw, IDirectDrawSurface *backbuffer, IDirect3DRMDevice **device)
+{
+    FIXME("iface %p, guid %s, ddraw %p, backbuffer %p, device %p partial stub.\n",
+            iface, debugstr_guid(guid), ddraw, backbuffer, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm1_CreateDeviceFromD3D(IDirect3DRM *iface,
+        IDirect3D *d3d, IDirect3DDevice *d3d_device, IDirect3DRMDevice **device)
+{
+    FIXME("iface %p, d3d %p, d3d_device %p, device %p partial stub.\n",
+            iface, d3d, d3d_device, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm1_CreateDeviceFromClipper(IDirect3DRM *iface,
+        IDirectDrawClipper *clipper, GUID *guid, int width, int height,
+        IDirect3DRMDevice **device)
+{
+    FIXME("iface %p, clipper %p, guid %s, width %d, height %d, device %p.\n",
+            iface, clipper, debugstr_guid(guid), width, height, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm1_CreateTextureFromSurface(IDirect3DRM *iface,
+        IDirectDrawSurface *surface, IDirect3DRMTexture **texture)
+{
+    FIXME("iface %p, surface %p, texture %p stub!\n", iface, surface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_CreateShadow(IDirect3DRM *iface, IDirect3DRMVisual *visual,
+        IDirect3DRMLight *light, D3DVALUE px, D3DVALUE py, D3DVALUE pz, D3DVALUE nx, D3DVALUE ny, D3DVALUE nz,
+        IDirect3DRMVisual **shadow)
+{
+    FIXME("iface %p, visual %p, light %p, px %.8e, py %.8e, pz %.8e, nx %.8e, ny %.8e, nz %.8e, shadow %p stub!\n",
+            iface, visual, light, px, py, pz, nx, ny, nz, shadow);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_CreateViewport(IDirect3DRM *iface, IDirect3DRMDevice *device,
+        IDirect3DRMFrame *camera, DWORD x, DWORD y, DWORD width, DWORD height, IDirect3DRMViewport **viewport)
+{
+    FIXME("iface %p, device %p, camera %p, x %u, y %u, width %u, height %u, viewport %p partial stub!\n",
+            iface, device, camera, x, y, width, height, viewport);
+
+    return Direct3DRMViewport_create(&IID_IDirect3DRMViewport, (IUnknown **)viewport);
+}
+
+static HRESULT WINAPI d3drm1_CreateWrap(IDirect3DRM *iface, D3DRMWRAPTYPE type, IDirect3DRMFrame *frame,
+        D3DVALUE ox, D3DVALUE oy, D3DVALUE oz, D3DVALUE dx, D3DVALUE dy, D3DVALUE dz,
+        D3DVALUE ux, D3DVALUE uy, D3DVALUE uz, D3DVALUE ou, D3DVALUE ov, D3DVALUE su, D3DVALUE sv,
+        IDirect3DRMWrap **wrap)
+{
+    FIXME("iface %p, type %#x, frame %p, ox %.8e, oy %.8e, oz %.8e, dx %.8e, dy %.8e, dz %.8e, "
+            "ux %.8e, uy %.8e, uz %.8e, ou %.8e, ov %.8e, su %.8e, sv %.8e, wrap %p stub!\n",
+            iface, type, frame, ox, oy, oz, dx, dy, dz, ux, uy, uz, ou, ov, su, sv, wrap);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_CreateUserVisual(IDirect3DRM *iface,
+        D3DRMUSERVISUALCALLBACK cb, void *ctx, IDirect3DRMUserVisual **visual)
+{
+    FIXME("iface %p, cb %p, ctx %p visual %p stub!\n", iface, cb, ctx, visual);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_LoadTexture(IDirect3DRM *iface,
+        const char *filename, IDirect3DRMTexture **texture)
+{
+    FIXME("iface %p, filename %s, texture %p stub!\n", iface, debugstr_a(filename), texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm1_LoadTextureFromResource(IDirect3DRM *iface,
+        HRSRC resource, IDirect3DRMTexture **texture)
+{
+    FIXME("iface %p, resource %p, texture %p stub!\n", iface, resource, texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm1_SetSearchPath(IDirect3DRM *iface, const char *path)
+{
+    FIXME("iface %p, path %s stub!\n", iface, debugstr_a(path));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_AddSearchPath(IDirect3DRM *iface, const char *path)
+{
+    FIXME("iface %p, path %s stub!\n", iface, debugstr_a(path));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_GetSearchPath(IDirect3DRM *iface, DWORD *size, char *path)
+{
+    FIXME("iface %p, size %p, path %p stub!\n", iface, size, path);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_SetDefaultTextureColors(IDirect3DRM *iface, DWORD color_count)
+{
+    FIXME("iface %p, color_count %u stub!\n", iface, color_count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_SetDefaultTextureShades(IDirect3DRM *iface, DWORD shade_count)
+{
+    FIXME("iface %p, shade_count %u stub!\n", iface, shade_count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_GetDevices(IDirect3DRM *iface, IDirect3DRMDeviceArray **array)
+{
+    FIXME("iface %p, array %p stub!\n", iface, array);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_GetNamedObject(IDirect3DRM *iface,
+        const char *name, IDirect3DRMObject **object)
+{
+    FIXME("iface %p, name %s, object %p stub!\n", iface, debugstr_a(name), object);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_EnumerateObjects(IDirect3DRM *iface, D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm1_Load(IDirect3DRM *iface, void *source, void *object_id, IID **iids,
+        DWORD iid_count, D3DRMLOADOPTIONS flags, D3DRMLOADCALLBACK load_cb, void *load_ctx,
+        D3DRMLOADTEXTURECALLBACK load_tex_cb, void *load_tex_ctx, IDirect3DRMFrame *parent_frame)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM(iface);
+    IDirect3DRMFrame3 *parent_frame3 = NULL;
+    HRESULT hr = D3DRM_OK;
+
+    TRACE("iface %p, source %p, object_id %p, iids %p, iid_count %u, flags %#x, "
+            "load_cb %p, load_ctx %p, load_tex_cb %p, load_tex_ctx %p, parent_frame %p.\n",
+            iface, source, object_id, iids, iid_count, flags,
+            load_cb, load_ctx, load_tex_cb, load_tex_ctx, parent_frame);
+
+    if (parent_frame)
+        hr = IDirect3DRMFrame_QueryInterface(parent_frame, &IID_IDirect3DRMFrame3, (void **)&parent_frame3);
+    if (SUCCEEDED(hr))
+        hr = IDirect3DRM3_Load(&d3drm->IDirect3DRM3_iface, source, object_id, iids, iid_count,
+                flags, load_cb, load_ctx, load_tex_cb, load_tex_ctx, parent_frame3);
+    if (parent_frame3)
+        IDirect3DRMFrame3_Release(parent_frame3);
+
+    return hr;
+}
+
+static HRESULT WINAPI d3drm1_Tick(IDirect3DRM *iface, D3DVALUE tick)
+{
+    FIXME("iface %p, tick %.8e stub!\n", iface, tick);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMVtbl d3drm1_vtbl =
+{
+    d3drm1_QueryInterface,
+    d3drm1_AddRef,
+    d3drm1_Release,
+    d3drm1_CreateObject,
+    d3drm1_CreateFrame,
+    d3drm1_CreateMesh,
+    d3drm1_CreateMeshBuilder,
+    d3drm1_CreateFace,
+    d3drm1_CreateAnimation,
+    d3drm1_CreateAnimationSet,
+    d3drm1_CreateTexture,
+    d3drm1_CreateLight,
+    d3drm1_CreateLightRGB,
+    d3drm1_CreateMaterial,
+    d3drm1_CreateDevice,
+    d3drm1_CreateDeviceFromSurface,
+    d3drm1_CreateDeviceFromD3D,
+    d3drm1_CreateDeviceFromClipper,
+    d3drm1_CreateTextureFromSurface,
+    d3drm1_CreateShadow,
+    d3drm1_CreateViewport,
+    d3drm1_CreateWrap,
+    d3drm1_CreateUserVisual,
+    d3drm1_LoadTexture,
+    d3drm1_LoadTextureFromResource,
+    d3drm1_SetSearchPath,
+    d3drm1_AddSearchPath,
+    d3drm1_GetSearchPath,
+    d3drm1_SetDefaultTextureColors,
+    d3drm1_SetDefaultTextureShades,
+    d3drm1_GetDevices,
+    d3drm1_GetNamedObject,
+    d3drm1_EnumerateObjects,
+    d3drm1_Load,
+    d3drm1_Tick,
+};
+
+static HRESULT WINAPI d3drm2_QueryInterface(IDirect3DRM2 *iface, REFIID riid, void **out)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM2(iface);
+
+    return d3drm1_QueryInterface(&d3drm->IDirect3DRM_iface, riid, out);
+}
+
+static ULONG WINAPI d3drm2_AddRef(IDirect3DRM2 *iface)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM2(iface);
+
+    return d3drm1_AddRef(&d3drm->IDirect3DRM_iface);
+}
+
+static ULONG WINAPI d3drm2_Release(IDirect3DRM2 *iface)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM2(iface);
+
+    return d3drm1_Release(&d3drm->IDirect3DRM_iface);
+}
+
+static HRESULT WINAPI d3drm2_CreateObject(IDirect3DRM2 *iface,
+        REFCLSID clsid, IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, clsid %s, outer %p, iid %s, out %p stub!\n",
+            iface, debugstr_guid(clsid), outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_CreateFrame(IDirect3DRM2 *iface,
+        IDirect3DRMFrame *parent_frame, IDirect3DRMFrame2 **frame)
+{
+    TRACE("iface %p, parent_frame %p, frame %p.\n", iface, parent_frame, frame);
+
+    return Direct3DRMFrame_create(&IID_IDirect3DRMFrame2, (IUnknown*)parent_frame, (IUnknown**)frame);
+}
+
+static HRESULT WINAPI d3drm2_CreateMesh(IDirect3DRM2 *iface, IDirect3DRMMesh **mesh)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM2(iface);
+
+    TRACE("iface %p, mesh %p.\n", iface, mesh);
+
+    return IDirect3DRM3_CreateMesh(&d3drm->IDirect3DRM3_iface, mesh);
+}
+
+static HRESULT WINAPI d3drm2_CreateMeshBuilder(IDirect3DRM2 *iface, IDirect3DRMMeshBuilder2 **mesh_builder)
+{
+    TRACE("iface %p, mesh_builder %p.\n", iface, mesh_builder);
+
+    return Direct3DRMMeshBuilder_create(&IID_IDirect3DRMMeshBuilder2, (IUnknown **)mesh_builder);
+}
+
+static HRESULT WINAPI d3drm2_CreateFace(IDirect3DRM2 *iface, IDirect3DRMFace **face)
+{
+    TRACE("iface %p, face %p.\n", iface, face);
+
+    return Direct3DRMFace_create(&IID_IDirect3DRMFace, (IUnknown **)face);
+}
+
+static HRESULT WINAPI d3drm2_CreateAnimation(IDirect3DRM2 *iface, IDirect3DRMAnimation **animation)
+{
+    FIXME("iface %p, animation %p stub!\n", iface, animation);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_CreateAnimationSet(IDirect3DRM2 *iface, IDirect3DRMAnimationSet **set)
+{
+    FIXME("iface %p, set %p stub!\n", iface, set);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_CreateTexture(IDirect3DRM2 *iface,
+        D3DRMIMAGE *image, IDirect3DRMTexture2 **texture)
+{
+    FIXME("iface %p, image %p, texture %p partial stub.\n", iface, image, texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture2, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm2_CreateLight(IDirect3DRM2 *iface,
+        D3DRMLIGHTTYPE type, D3DCOLOR color, IDirect3DRMLight **light)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM2(iface);
+
+    TRACE("iface %p, type %#x, color 0x%08x, light %p.\n", iface, type, color, light);
+
+    return IDirect3DRM3_CreateLight(&d3drm->IDirect3DRM3_iface, type, color, light);
+}
+
+static HRESULT WINAPI d3drm2_CreateLightRGB(IDirect3DRM2 *iface, D3DRMLIGHTTYPE type,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue, IDirect3DRMLight **light)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM2(iface);
+
+    TRACE("iface %p, type %#x, red %.8e, green %.8e, blue %.8e, light %p.\n",
+            iface, type, red, green, blue, light);
+
+    return IDirect3DRM3_CreateLightRGB(&d3drm->IDirect3DRM3_iface, type, red, green, blue, light);
+}
+
+static HRESULT WINAPI d3drm2_CreateMaterial(IDirect3DRM2 *iface,
+        D3DVALUE power, IDirect3DRMMaterial **material)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM2(iface);
+
+    TRACE("iface %p, power %.8e, material %p.\n", iface, power, material);
+
+    return IDirect3DRM3_CreateMaterial(&d3drm->IDirect3DRM3_iface, power, (IDirect3DRMMaterial2 **)material);
+}
+
+static HRESULT WINAPI d3drm2_CreateDevice(IDirect3DRM2 *iface,
+        DWORD width, DWORD height, IDirect3DRMDevice2 **device)
+{
+    FIXME("iface %p, width %u, height %u, device %p.\n", iface, width, height, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice2, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm2_CreateDeviceFromSurface(IDirect3DRM2 *iface, GUID *guid,
+        IDirectDraw *ddraw, IDirectDrawSurface *backbuffer, IDirect3DRMDevice2 **device)
+{
+    FIXME("iface %p, guid %s, ddraw %p, backbuffer %p, device %p partial stub.\n",
+            iface, debugstr_guid(guid), ddraw, backbuffer, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice2, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm2_CreateDeviceFromD3D(IDirect3DRM2 *iface,
+        IDirect3D2 *d3d, IDirect3DDevice2 *d3d_device, IDirect3DRMDevice2 **device)
+{
+    FIXME("iface %p, d3d %p, d3d_device %p, device %p partial stub.\n",
+            iface, d3d, d3d_device, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice2, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm2_CreateDeviceFromClipper(IDirect3DRM2 *iface,
+        IDirectDrawClipper *clipper, GUID *guid, int width, int height,
+        IDirect3DRMDevice2 **device)
+{
+    FIXME("iface %p, clipper %p, guid %s, width %d, height %d, device %p partial stub.\n",
+            iface, clipper, debugstr_guid(guid), width, height, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice2, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm2_CreateTextureFromSurface(IDirect3DRM2 *iface,
+        IDirectDrawSurface *surface, IDirect3DRMTexture2 **texture)
+{
+    FIXME("iface %p, surface %p, texture %p stub!\n", iface, surface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_CreateShadow(IDirect3DRM2 *iface, IDirect3DRMVisual *visual,
+        IDirect3DRMLight *light, D3DVALUE px, D3DVALUE py, D3DVALUE pz, D3DVALUE nx, D3DVALUE ny, D3DVALUE nz,
+        IDirect3DRMVisual **shadow)
+{
+    FIXME("iface %p, visual %p, light %p, px %.8e, py %.8e, pz %.8e, nx %.8e, ny %.8e, nz %.8e, shadow %p stub!\n",
+            iface, visual, light, px, py, pz, nx, ny, nz, shadow);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_CreateViewport(IDirect3DRM2 *iface, IDirect3DRMDevice *device,
+        IDirect3DRMFrame *camera, DWORD x, DWORD y, DWORD width, DWORD height, IDirect3DRMViewport **viewport)
+{
+    FIXME("iface %p, device %p, camera %p, x %u, y %u, width %u, height %u, viewport %p partial stub!\n",
+            iface, device, camera, x, y, width, height, viewport);
+
+    return Direct3DRMViewport_create(&IID_IDirect3DRMViewport, (IUnknown **)viewport);
+}
+
+static HRESULT WINAPI d3drm2_CreateWrap(IDirect3DRM2 *iface, D3DRMWRAPTYPE type, IDirect3DRMFrame *frame,
+        D3DVALUE ox, D3DVALUE oy, D3DVALUE oz, D3DVALUE dx, D3DVALUE dy, D3DVALUE dz,
+        D3DVALUE ux, D3DVALUE uy, D3DVALUE uz, D3DVALUE ou, D3DVALUE ov, D3DVALUE su, D3DVALUE sv,
+        IDirect3DRMWrap **wrap)
+{
+    FIXME("iface %p, type %#x, frame %p, ox %.8e, oy %.8e, oz %.8e, dx %.8e, dy %.8e, dz %.8e, "
+            "ux %.8e, uy %.8e, uz %.8e, ou %.8e, ov %.8e, su %.8e, sv %.8e, wrap %p stub!\n",
+            iface, type, frame, ox, oy, oz, dx, dy, dz, ux, uy, uz, ou, ov, su, sv, wrap);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_CreateUserVisual(IDirect3DRM2 *iface,
+        D3DRMUSERVISUALCALLBACK cb, void *ctx, IDirect3DRMUserVisual **visual)
+{
+    FIXME("iface %p, cb %p, ctx %p, visual %p stub!\n", iface, cb, ctx, visual);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_LoadTexture(IDirect3DRM2 *iface,
+        const char *filename, IDirect3DRMTexture2 **texture)
+{
+    FIXME("iface %p, filename %s, texture %p stub!\n", iface, debugstr_a(filename), texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture2, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm2_LoadTextureFromResource(IDirect3DRM2 *iface, HMODULE module,
+        const char *resource_name, const char *resource_type, IDirect3DRMTexture2 **texture)
+{
+    FIXME("iface %p, resource_name %s, resource_type %s, texture %p stub!\n",
+            iface, debugstr_a(resource_name), debugstr_a(resource_type), texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture2, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm2_SetSearchPath(IDirect3DRM2 *iface, const char *path)
+{
+    FIXME("iface %p, path %s stub!\n", iface, debugstr_a(path));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_AddSearchPath(IDirect3DRM2 *iface, const char *path)
+{
+    FIXME("iface %p, path %s stub!\n", iface, debugstr_a(path));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_GetSearchPath(IDirect3DRM2 *iface, DWORD *size, char *path)
+{
+    FIXME("iface %p, size %p, path %p stub!\n", iface, size, path);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_SetDefaultTextureColors(IDirect3DRM2 *iface, DWORD color_count)
+{
+    FIXME("iface %p, color_count %u stub!\n", iface, color_count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_SetDefaultTextureShades(IDirect3DRM2 *iface, DWORD shade_count)
+{
+    FIXME("iface %p, shade_count %u stub!\n", iface, shade_count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_GetDevices(IDirect3DRM2 *iface, IDirect3DRMDeviceArray **array)
+{
+    FIXME("iface %p, array %p stub!\n", iface, array);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_GetNamedObject(IDirect3DRM2 *iface,
+        const char *name, IDirect3DRMObject **object)
+{
+    FIXME("iface %p, name %s, object %p stub!\n", iface, debugstr_a(name), object);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_EnumerateObjects(IDirect3DRM2 *iface, D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_Load(IDirect3DRM2 *iface, void *source, void *object_id, IID **iids,
+        DWORD iid_count, D3DRMLOADOPTIONS flags, D3DRMLOADCALLBACK load_cb, void *load_ctx,
+        D3DRMLOADTEXTURECALLBACK load_tex_cb, void *load_tex_ctx, IDirect3DRMFrame *parent_frame)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM2(iface);
+    IDirect3DRMFrame3 *parent_frame3 = NULL;
+    HRESULT hr = D3DRM_OK;
+
+    TRACE("iface %p, source %p, object_id %p, iids %p, iid_count %u, flags %#x, "
+            "load_cb %p, load_ctx %p, load_tex_cb %p, load_tex_ctx %p, parent_frame %p.\n",
+            iface, source, object_id, iids, iid_count, flags,
+            load_cb, load_ctx, load_tex_cb, load_tex_ctx, parent_frame);
+
+    if (parent_frame)
+        hr = IDirect3DRMFrame_QueryInterface(parent_frame, &IID_IDirect3DRMFrame3, (void **)&parent_frame3);
+    if (SUCCEEDED(hr))
+        hr = IDirect3DRM3_Load(&d3drm->IDirect3DRM3_iface, source, object_id, iids, iid_count,
+                flags, load_cb, load_ctx, load_tex_cb, load_tex_ctx, parent_frame3);
+    if (parent_frame3)
+        IDirect3DRMFrame3_Release(parent_frame3);
+
+    return hr;
+}
+
+static HRESULT WINAPI d3drm2_Tick(IDirect3DRM2 *iface, D3DVALUE tick)
+{
+    FIXME("iface %p, tick %.8e stub!\n", iface, tick);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm2_CreateProgressiveMesh(IDirect3DRM2 *iface, IDirect3DRMProgressiveMesh **mesh)
+{
+    FIXME("iface %p, mesh %p stub!\n", iface, mesh);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRM2Vtbl d3drm2_vtbl =
+{
+    d3drm2_QueryInterface,
+    d3drm2_AddRef,
+    d3drm2_Release,
+    d3drm2_CreateObject,
+    d3drm2_CreateFrame,
+    d3drm2_CreateMesh,
+    d3drm2_CreateMeshBuilder,
+    d3drm2_CreateFace,
+    d3drm2_CreateAnimation,
+    d3drm2_CreateAnimationSet,
+    d3drm2_CreateTexture,
+    d3drm2_CreateLight,
+    d3drm2_CreateLightRGB,
+    d3drm2_CreateMaterial,
+    d3drm2_CreateDevice,
+    d3drm2_CreateDeviceFromSurface,
+    d3drm2_CreateDeviceFromD3D,
+    d3drm2_CreateDeviceFromClipper,
+    d3drm2_CreateTextureFromSurface,
+    d3drm2_CreateShadow,
+    d3drm2_CreateViewport,
+    d3drm2_CreateWrap,
+    d3drm2_CreateUserVisual,
+    d3drm2_LoadTexture,
+    d3drm2_LoadTextureFromResource,
+    d3drm2_SetSearchPath,
+    d3drm2_AddSearchPath,
+    d3drm2_GetSearchPath,
+    d3drm2_SetDefaultTextureColors,
+    d3drm2_SetDefaultTextureShades,
+    d3drm2_GetDevices,
+    d3drm2_GetNamedObject,
+    d3drm2_EnumerateObjects,
+    d3drm2_Load,
+    d3drm2_Tick,
+    d3drm2_CreateProgressiveMesh,
+};
+
+static HRESULT WINAPI d3drm3_QueryInterface(IDirect3DRM3 *iface, REFIID riid, void **out)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM3(iface);
+
+    return d3drm1_QueryInterface(&d3drm->IDirect3DRM_iface, riid, out);
+}
+
+static ULONG WINAPI d3drm3_AddRef(IDirect3DRM3 *iface)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM3(iface);
+
+    return d3drm1_AddRef(&d3drm->IDirect3DRM_iface);
+}
+
+static ULONG WINAPI d3drm3_Release(IDirect3DRM3 *iface)
+{
+    struct d3drm *d3drm = impl_from_IDirect3DRM3(iface);
+
+    return d3drm1_Release(&d3drm->IDirect3DRM_iface);
+}
+
+static HRESULT WINAPI d3drm3_CreateObject(IDirect3DRM3 *iface,
+        REFCLSID clsid, IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, clsid %s, outer %p, iid %s, out %p stub!\n",
+            iface, debugstr_guid(clsid), outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_CreateFrame(IDirect3DRM3 *iface,
+        IDirect3DRMFrame3 *parent, IDirect3DRMFrame3 **frame)
+{
+    TRACE("iface %p, parent %p, frame %p.\n", iface, parent, frame);
+
+    return Direct3DRMFrame_create(&IID_IDirect3DRMFrame3, (IUnknown *)parent, (IUnknown **)frame);
+}
+
+static HRESULT WINAPI d3drm3_CreateMesh(IDirect3DRM3 *iface, IDirect3DRMMesh **mesh)
+{
+    TRACE("iface %p, mesh %p.\n", iface, mesh);
+
+    return Direct3DRMMesh_create(mesh);
+}
+
+static HRESULT WINAPI d3drm3_CreateMeshBuilder(IDirect3DRM3 *iface, IDirect3DRMMeshBuilder3 **mesh_builder)
+{
+    TRACE("iface %p, mesh_builder %p.\n", iface, mesh_builder);
+
+    return Direct3DRMMeshBuilder_create(&IID_IDirect3DRMMeshBuilder3, (IUnknown **)mesh_builder);
+}
+
+static HRESULT WINAPI d3drm3_CreateFace(IDirect3DRM3 *iface, IDirect3DRMFace2 **face)
+{
+    TRACE("iface %p, face %p.\n", iface, face);
+
+    return Direct3DRMFace_create(&IID_IDirect3DRMFace2, (IUnknown **)face);
+}
+
+static HRESULT WINAPI d3drm3_CreateAnimation(IDirect3DRM3 *iface, IDirect3DRMAnimation2 **animation)
+{
+    FIXME("iface %p, animation %p stub!\n", iface, animation);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_CreateAnimationSet(IDirect3DRM3 *iface, IDirect3DRMAnimationSet2 **set)
+{
+    FIXME("iface %p, set %p stub!\n", iface, set);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_CreateTexture(IDirect3DRM3 *iface,
+        D3DRMIMAGE *image, IDirect3DRMTexture3 **texture)
+{
+    FIXME("iface %p, image %p, texture %p partial stub.\n", iface, image, texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture3, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm3_CreateLight(IDirect3DRM3 *iface,
+        D3DRMLIGHTTYPE type, D3DCOLOR color, IDirect3DRMLight **light)
+{
+    HRESULT hr;
+
+    FIXME("iface %p, type %#x, color 0x%08x, light %p partial stub!\n", iface, type, color, light);
+
+    if (SUCCEEDED(hr = Direct3DRMLight_create((IUnknown **)light)))
+    {
+        IDirect3DRMLight_SetType(*light, type);
+        IDirect3DRMLight_SetColor(*light, color);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI d3drm3_CreateLightRGB(IDirect3DRM3 *iface, D3DRMLIGHTTYPE type,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue, IDirect3DRMLight **light)
+{
+    HRESULT hr;
+
+    FIXME("iface %p, type %#x, red %.8e, green %.8e, blue %.8e, light %p partial stub!\n",
+            iface, type, red, green, blue, light);
+
+    if (SUCCEEDED(hr = Direct3DRMLight_create((IUnknown **)light)))
+    {
+        IDirect3DRMLight_SetType(*light, type);
+        IDirect3DRMLight_SetColorRGB(*light, red, green, blue);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI d3drm3_CreateMaterial(IDirect3DRM3 *iface,
+        D3DVALUE power, IDirect3DRMMaterial2 **material)
+{
+    HRESULT hr;
+
+    TRACE("iface %p, power %.8e, material %p.\n", iface, power, material);
+
+    if (SUCCEEDED(hr = Direct3DRMMaterial_create(material)))
+        IDirect3DRMMaterial2_SetPower(*material, power);
+
+    return hr;
+}
+
+static HRESULT WINAPI d3drm3_CreateDevice(IDirect3DRM3 *iface,
+        DWORD width, DWORD height, IDirect3DRMDevice3 **device)
+{
+    FIXME("iface %p, width %u, height %u, device %p partial stub!\n", iface, width, height, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice3, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm3_CreateDeviceFromSurface(IDirect3DRM3 *iface, GUID *guid,
+        IDirectDraw *ddraw, IDirectDrawSurface *backbuffer, IDirect3DRMDevice3 **device)
+{
+    FIXME("iface %p, guid %s, ddraw %p, backbuffer %p, device %p partial stub.\n",
+            iface, debugstr_guid(guid), ddraw, backbuffer, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice3, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm3_CreateDeviceFromD3D(IDirect3DRM3 *iface,
+        IDirect3D2 *d3d, IDirect3DDevice2 *d3d_device, IDirect3DRMDevice3 **device)
+{
+    FIXME("iface %p, d3d %p, d3d_device %p, device %p partial stub.\n",
+            iface, d3d, d3d_device, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice3, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm3_CreateDeviceFromClipper(IDirect3DRM3 *iface,
+        IDirectDrawClipper *clipper, GUID *guid, int width, int height,
+        IDirect3DRMDevice3 **device)
+{
+    FIXME("iface %p, clipper %p, guid %s, width %d, height %d, device %p partial stub.\n",
+            iface, clipper, debugstr_guid(guid), width, height, device);
+
+    return Direct3DRMDevice_create(&IID_IDirect3DRMDevice3, (IUnknown **)device);
+}
+
+static HRESULT WINAPI d3drm3_CreateShadow(IDirect3DRM3 *iface, IUnknown *object, IDirect3DRMLight *light,
+        D3DVALUE px, D3DVALUE py, D3DVALUE pz, D3DVALUE nx, D3DVALUE ny, D3DVALUE nz, IDirect3DRMShadow2 **shadow)
+{
+    FIXME("iface %p, object %p, light %p, px %.8e, py %.8e, pz %.8e, nx %.8e, ny %.8e, nz %.8e, shadow %p stub!\n",
+            iface, object, light, px, py, pz, nx, ny, nz, shadow);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_CreateTextureFromSurface(IDirect3DRM3 *iface,
+        IDirectDrawSurface *surface, IDirect3DRMTexture3 **texture)
+{
+    FIXME("iface %p, surface %p, texture %p stub!\n", iface, surface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_CreateViewport(IDirect3DRM3 *iface, IDirect3DRMDevice3 *device,
+        IDirect3DRMFrame3 *camera, DWORD x, DWORD y, DWORD width, DWORD height, IDirect3DRMViewport2 **viewport)
+{
+    FIXME("iface %p, device %p, camera %p, x %u, y %u, width %u, height %u, viewport %p partial stub!\n",
+            iface, device, camera, x, y, width, height, viewport);
+
+    return Direct3DRMViewport_create(&IID_IDirect3DRMViewport2, (IUnknown **)viewport);
+}
+
+static HRESULT WINAPI d3drm3_CreateWrap(IDirect3DRM3 *iface, D3DRMWRAPTYPE type, IDirect3DRMFrame3 *frame,
+        D3DVALUE ox, D3DVALUE oy, D3DVALUE oz, D3DVALUE dx, D3DVALUE dy, D3DVALUE dz,
+        D3DVALUE ux, D3DVALUE uy, D3DVALUE uz, D3DVALUE ou, D3DVALUE ov, D3DVALUE su, D3DVALUE sv,
+        IDirect3DRMWrap **wrap)
+{
+    FIXME("iface %p, type %#x, frame %p, ox %.8e, oy %.8e, oz %.8e, dx %.8e, dy %.8e, dz %.8e, "
+            "ux %.8e, uy %.8e, uz %.8e, ou %.8e, ov %.8e, su %.8e, sv %.8e, wrap %p stub!\n",
+            iface, type, frame, ox, oy, oz, dx, dy, dz, ux, uy, uz, ou, ov, su, sv, wrap);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_CreateUserVisual(IDirect3DRM3 *iface,
+        D3DRMUSERVISUALCALLBACK cb, void *ctx, IDirect3DRMUserVisual **visual)
+{
+    FIXME("iface %p, cb %p, ctx %p, visual %p stub!\n", iface, cb, ctx, visual);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_LoadTexture(IDirect3DRM3 *iface,
+        const char *filename, IDirect3DRMTexture3 **texture)
+{
+    FIXME("iface %p, filename %s, texture %p stub!\n", iface, debugstr_a(filename), texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture3, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm3_LoadTextureFromResource(IDirect3DRM3 *iface, HMODULE module,
+        const char *resource_name, const char *resource_type, IDirect3DRMTexture3 **texture)
+{
+    FIXME("iface %p, module %p, resource_name %s, resource_type %s, texture %p stub!\n",
+            iface, module, debugstr_a(resource_name), debugstr_a(resource_type), texture);
+
+    return Direct3DRMTexture_create(&IID_IDirect3DRMTexture3, (IUnknown **)texture);
+}
+
+static HRESULT WINAPI d3drm3_SetSearchPath(IDirect3DRM3 *iface, const char *path)
+{
+    FIXME("iface %p, path %s stub!\n", iface, debugstr_a(path));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_AddSearchPath(IDirect3DRM3 *iface, const char *path)
+{
+    FIXME("iface %p, path %s stub!\n", iface, debugstr_a(path));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_GetSearchPath(IDirect3DRM3 *iface, DWORD *size, char *path)
+{
+    FIXME("iface %p, size %p, path %p stub!\n", iface, size, path);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_SetDefaultTextureColors(IDirect3DRM3 *iface, DWORD color_count)
+{
+    FIXME("iface %p, color_count %u stub!\n", iface, color_count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_SetDefaultTextureShades(IDirect3DRM3 *iface, DWORD shade_count)
+{
+    FIXME("iface %p, shade_count %u stub!\n", iface, shade_count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_GetDevices(IDirect3DRM3 *iface, IDirect3DRMDeviceArray **array)
+{
+    FIXME("iface %p, array %p stub!\n", iface, array);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_GetNamedObject(IDirect3DRM3 *iface,
+        const char *name, IDirect3DRMObject **object)
+{
+    FIXME("iface %p, name %s, object %p stub!\n", iface, debugstr_a(name), object);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_EnumerateObjects(IDirect3DRM3 *iface, D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT load_data(IDirect3DRM3 *iface, IDirectXFileData *data_object, IID **GUIDs, DWORD nb_GUIDs, D3DRMLOADCALLBACK LoadProc,
+                         void *ArgLP, D3DRMLOADTEXTURECALLBACK LoadTextureProc, void *ArgLTP, IDirect3DRMFrame3 *parent_frame)
+{
+    HRESULT ret = D3DRMERR_BADOBJECT;
+    HRESULT hr;
+    const GUID* guid;
+    DWORD i;
+    BOOL requested = FALSE;
+
+    hr = IDirectXFileData_GetType(data_object, &guid);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    TRACE("Found object type whose GUID = %s\n", debugstr_guid(guid));
+
+    /* Load object only if it is top level and requested or if it is part of another object */
+
+    if (IsEqualGUID(guid, &TID_D3DRMMesh))
+    {
+        TRACE("Found TID_D3DRMMesh\n");
+
+        for (i = 0; i < nb_GUIDs; i++)
+            if (IsEqualGUID(GUIDs[i], &IID_IDirect3DRMMeshBuilder) ||
+                IsEqualGUID(GUIDs[i], &IID_IDirect3DRMMeshBuilder2) ||
+                IsEqualGUID(GUIDs[i], &IID_IDirect3DRMMeshBuilder3))
+            {
+                requested = TRUE;
+                break;
+            }
+
+        if (requested || parent_frame)
+        {
+            IDirect3DRMMeshBuilder3 *meshbuilder;
+
+            TRACE("Load mesh data\n");
+
+            hr = IDirect3DRM3_CreateMeshBuilder(iface, &meshbuilder);
+            if (SUCCEEDED(hr))
+            {
+                hr = load_mesh_data(meshbuilder, data_object, LoadTextureProc, ArgLTP);
+                if (SUCCEEDED(hr))
+                {
+                    /* Only top level objects are notified */
+                    if (!parent_frame)
+                    {
+                        IDirect3DRMObject *object;
+
+                        hr = IDirect3DRMMeshBuilder3_QueryInterface(meshbuilder, GUIDs[i], (void**)&object);
+                        if (SUCCEEDED(hr))
+                        {
+                            LoadProc(object, GUIDs[i], ArgLP);
+                            IDirect3DRMObject_Release(object);
+                        }
+                    }
+                    else
+                    {
+                        IDirect3DRMFrame3_AddVisual(parent_frame, (IUnknown*)meshbuilder);
+                    }
+                }
+                IDirect3DRMMeshBuilder3_Release(meshbuilder);
+            }
+
+            if (FAILED(hr))
+                ERR("Cannot process mesh\n");
+        }
+    }
+    else if (IsEqualGUID(guid, &TID_D3DRMFrame))
+    {
+        TRACE("Found TID_D3DRMFrame\n");
+
+        for (i = 0; i < nb_GUIDs; i++)
+            if (IsEqualGUID(GUIDs[i], &IID_IDirect3DRMFrame) ||
+                IsEqualGUID(GUIDs[i], &IID_IDirect3DRMFrame2) ||
+                IsEqualGUID(GUIDs[i], &IID_IDirect3DRMFrame3))
+            {
+                requested = TRUE;
+                break;
+            }
+
+        if (requested || parent_frame)
+        {
+            IDirect3DRMFrame3 *frame;
+
+            TRACE("Load frame data\n");
+
+            hr = IDirect3DRM3_CreateFrame(iface, parent_frame, &frame);
+            if (SUCCEEDED(hr))
+            {
+                IDirectXFileObject *child;
+
+                while (SUCCEEDED(hr = IDirectXFileData_GetNextObject(data_object, &child)))
+                {
+                    IDirectXFileData *data;
+                    IDirectXFileDataReference *reference;
+                    IDirectXFileBinary *binary;
+
+                    hr = IDirectXFileObject_QueryInterface(child, &IID_IDirectXFileBinary, (void **)&binary);
+                    if (SUCCEEDED(hr))
+                    {
+                        FIXME("Binary Object not supported yet\n");
+                        IDirectXFileBinary_Release(binary);
+                        continue;
+                    }
+
+                    hr = IDirectXFileObject_QueryInterface(child, &IID_IDirectXFileData, (void **)&data);
+                    if (SUCCEEDED(hr))
+                    {
+                        TRACE("Found Data Object\n");
+                        hr = load_data(iface, data, GUIDs, nb_GUIDs, LoadProc, ArgLP, LoadTextureProc, ArgLTP, frame);
+                        IDirectXFileData_Release(data);
+                        continue;
+                    }
+                    hr = IDirectXFileObject_QueryInterface(child, &IID_IDirectXFileDataReference, (void **)&reference);
+                    if (SUCCEEDED(hr))
+                    {
+                        TRACE("Found Data Object Reference\n");
+                        IDirectXFileDataReference_Resolve(reference, &data);
+                        hr = load_data(iface, data, GUIDs, nb_GUIDs, LoadProc, ArgLP, LoadTextureProc, ArgLTP, frame);
+                        IDirectXFileData_Release(data);
+                        IDirectXFileDataReference_Release(reference);
+                        continue;
+                    }
+                }
+
+                if (hr != DXFILEERR_NOMOREOBJECTS)
+                {
+                    IDirect3DRMFrame3_Release(frame);
+                    goto end;
+                }
+                hr = S_OK;
+
+                /* Only top level objects are notified */
+                if (!parent_frame)
+                {
+                    IDirect3DRMObject *object;
+
+                    hr = IDirect3DRMFrame3_QueryInterface(frame, GUIDs[i], (void**)&object);
+                    if (SUCCEEDED(hr))
+                    {
+                        LoadProc(object, GUIDs[i], ArgLP);
+                        IDirect3DRMObject_Release(object);
+                    }
+                }
+                IDirect3DRMFrame3_Release(frame);
+            }
+
+            if (FAILED(hr))
+                ERR("Cannot process frame\n");
+        }
+    }
+    else if (IsEqualGUID(guid, &TID_D3DRMMaterial))
+    {
+        TRACE("Found TID_D3DRMMaterial\n");
+
+        /* Cannot be requested so nothing to do */
+    }
+    else if (IsEqualGUID(guid, &TID_D3DRMFrameTransformMatrix))
+    {
+        TRACE("Found TID_D3DRMFrameTransformMatrix\n");
+
+        /* Cannot be requested */
+        if (parent_frame)
+        {
+            D3DRMMATRIX4D matrix;
+            DWORD size;
+
+            TRACE("Load Frame Transform Matrix data\n");
+
+            size = sizeof(matrix);
+            hr = IDirectXFileData_GetData(data_object, NULL, &size, (void**)matrix);
+            if ((hr != DXFILE_OK) || (size != sizeof(matrix)))
+                goto end;
+
+            hr = IDirect3DRMFrame3_AddTransform(parent_frame, D3DRMCOMBINE_REPLACE, matrix);
+            if (FAILED(hr))
+                goto end;
+        }
+    }
+    else
+    {
+        FIXME("Found unknown TID %s\n", debugstr_guid(guid));
+    }
+
+    ret = D3DRM_OK;
+
+end:
+
+    return ret;
+}
+
+static HRESULT WINAPI d3drm3_Load(IDirect3DRM3 *iface, void *source, void *object_id, IID **iids,
+        DWORD iid_count, D3DRMLOADOPTIONS flags, D3DRMLOADCALLBACK load_cb, void *load_ctx,
+        D3DRMLOADTEXTURECALLBACK load_tex_cb, void *load_tex_ctx, IDirect3DRMFrame3 *parent_frame)
+{
+    DXFILELOADOPTIONS load_options;
+    IDirectXFile *file = NULL;
+    IDirectXFileEnumObject *enum_object = NULL;
+    IDirectXFileData *data = NULL;
+    HRESULT hr;
+    const GUID* pGuid;
+    DWORD size;
+    struct d3drm_file_header *header;
+    HRESULT ret = D3DRMERR_BADOBJECT;
+    DWORD i;
+
+    TRACE("iface %p, source %p, object_id %p, iids %p, iid_count %u, flags %#x, "
+            "load_cb %p, load_ctx %p, load_tex_cb %p, load_tex_ctx %p, parent_frame %p.\n",
+            iface, source, object_id, iids, iid_count, flags,
+            load_cb, load_ctx, load_tex_cb, load_tex_ctx, parent_frame);
+
+    TRACE("Looking for GUIDs:\n");
+    for (i = 0; i < iid_count; ++i)
+        TRACE("- %s (%s)\n", debugstr_guid(iids[i]), get_IID_string(iids[i]));
+
+    if (flags == D3DRMLOAD_FROMMEMORY)
+    {
+        load_options = DXFILELOAD_FROMMEMORY;
+    }
+    else if (flags == D3DRMLOAD_FROMFILE)
+    {
+        load_options = DXFILELOAD_FROMFILE;
+        TRACE("Loading from file %s\n", debugstr_a(source));
+    }
+    else
+    {
+        FIXME("Load options %#x not supported yet.\n", flags);
+        return E_NOTIMPL;
+    }
+
+    hr = DirectXFileCreate(&file);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    hr = IDirectXFile_RegisterTemplates(file, templates, strlen(templates));
+    if (hr != DXFILE_OK)
+        goto end;
+
+    hr = IDirectXFile_CreateEnumObject(file, source, load_options, &enum_object);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    hr = IDirectXFileEnumObject_GetNextDataObject(enum_object, &data);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    hr = IDirectXFileData_GetType(data, &pGuid);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    TRACE("Found object type whose GUID = %s\n", debugstr_guid(pGuid));
+
+    if (!IsEqualGUID(pGuid, &TID_DXFILEHeader))
+    {
+        ret = D3DRMERR_BADFILE;
+        goto end;
+    }
+
+    hr = IDirectXFileData_GetData(data, NULL, &size, (void **)&header);
+    if ((hr != DXFILE_OK) || (size != sizeof(*header)))
+        goto end;
+
+    TRACE("Version is %u.%u, flags %#x.\n", header->major, header->minor, header->flags);
+
+    /* Version must be 1.0.x */
+    if ((header->major != 1) || (header->minor != 0))
+    {
+        ret = D3DRMERR_BADFILE;
+        goto end;
+    }
+
+    IDirectXFileData_Release(data);
+    data = NULL;
+
+    while (1)
+    {
+        hr = IDirectXFileEnumObject_GetNextDataObject(enum_object, &data);
+        if (hr == DXFILEERR_NOMOREOBJECTS)
+        {
+            TRACE("No more object\n");
+            break;
+        }
+        else if (hr != DXFILE_OK)
+        {
+            ret = D3DRMERR_BADFILE;
+            goto end;
+        }
+
+        ret = load_data(iface, data, iids, iid_count, load_cb, load_ctx, load_tex_cb, load_tex_ctx, parent_frame);
+        if (ret != D3DRM_OK)
+            goto end;
+
+        IDirectXFileData_Release(data);
+        data = NULL;
+    }
+
+    ret = D3DRM_OK;
+
+end:
+    if (data)
+        IDirectXFileData_Release(data);
+    if (enum_object)
+        IDirectXFileEnumObject_Release(enum_object);
+    if (file)
+        IDirectXFile_Release(file);
+
+    return ret;
+}
+
+static HRESULT WINAPI d3drm3_Tick(IDirect3DRM3 *iface, D3DVALUE tick)
+{
+    FIXME("iface %p, tick %.8e stub!\n", iface, tick);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_CreateProgressiveMesh(IDirect3DRM3 *iface, IDirect3DRMProgressiveMesh **mesh)
+{
+    FIXME("iface %p, mesh %p stub!\n", iface, mesh);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_RegisterClient(IDirect3DRM3 *iface, REFGUID guid, DWORD *id)
+{
+    FIXME("iface %p, guid %s, id %p stub!\n", iface, debugstr_guid(guid), id);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_UnregisterClient(IDirect3DRM3 *iface, REFGUID guid)
+{
+    FIXME("iface %p, guid %s stub!\n", iface, debugstr_guid(guid));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_CreateClippedVisual(IDirect3DRM3 *iface,
+        IDirect3DRMVisual *visual, IDirect3DRMClippedVisual **clipped_visual)
+{
+    FIXME("iface %p, visual %p, clipped_visual %p stub!\n", iface, visual, clipped_visual);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_SetOptions(IDirect3DRM3 *iface, DWORD flags)
+{
+    FIXME("iface %p, flags %#x stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm3_GetOptions(IDirect3DRM3 *iface, DWORD *flags)
+{
+    FIXME("iface %p, flags %p stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRM3Vtbl d3drm3_vtbl =
+{
+    d3drm3_QueryInterface,
+    d3drm3_AddRef,
+    d3drm3_Release,
+    d3drm3_CreateObject,
+    d3drm3_CreateFrame,
+    d3drm3_CreateMesh,
+    d3drm3_CreateMeshBuilder,
+    d3drm3_CreateFace,
+    d3drm3_CreateAnimation,
+    d3drm3_CreateAnimationSet,
+    d3drm3_CreateTexture,
+    d3drm3_CreateLight,
+    d3drm3_CreateLightRGB,
+    d3drm3_CreateMaterial,
+    d3drm3_CreateDevice,
+    d3drm3_CreateDeviceFromSurface,
+    d3drm3_CreateDeviceFromD3D,
+    d3drm3_CreateDeviceFromClipper,
+    d3drm3_CreateTextureFromSurface,
+    d3drm3_CreateShadow,
+    d3drm3_CreateViewport,
+    d3drm3_CreateWrap,
+    d3drm3_CreateUserVisual,
+    d3drm3_LoadTexture,
+    d3drm3_LoadTextureFromResource,
+    d3drm3_SetSearchPath,
+    d3drm3_AddSearchPath,
+    d3drm3_GetSearchPath,
+    d3drm3_SetDefaultTextureColors,
+    d3drm3_SetDefaultTextureShades,
+    d3drm3_GetDevices,
+    d3drm3_GetNamedObject,
+    d3drm3_EnumerateObjects,
+    d3drm3_Load,
+    d3drm3_Tick,
+    d3drm3_CreateProgressiveMesh,
+    d3drm3_RegisterClient,
+    d3drm3_UnregisterClient,
+    d3drm3_CreateClippedVisual,
+    d3drm3_SetOptions,
+    d3drm3_GetOptions,
+};
+
+HRESULT WINAPI Direct3DRMCreate(IDirect3DRM **d3drm)
+{
+    struct d3drm *object;
+
+    TRACE("d3drm %p.\n", d3drm);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRM_iface.lpVtbl = &d3drm1_vtbl;
+    object->IDirect3DRM2_iface.lpVtbl = &d3drm2_vtbl;
+    object->IDirect3DRM3_iface.lpVtbl = &d3drm3_vtbl;
+    object->ref = 1;
+
+    *d3drm = &object->IDirect3DRM_iface;
+
+    return S_OK;
+}
diff --git a/reactos/dll/directx/wine/d3drm/d3drm.spec b/reactos/dll/directx/wine/d3drm/d3drm.spec
new file mode 100644 (file)
index 0000000..4108a72
--- /dev/null
@@ -0,0 +1,23 @@
+@ stdcall D3DRMColorGetAlpha(long)
+@ stdcall D3DRMColorGetBlue(long)
+@ stdcall D3DRMColorGetGreen(long)
+@ stdcall D3DRMColorGetRed(long)
+@ stdcall D3DRMCreateColorRGB(float float float)
+@ stdcall D3DRMCreateColorRGBA(float float float float)
+@ stdcall D3DRMMatrixFromQuaternion(ptr ptr)
+@ stdcall D3DRMQuaternionFromRotation(ptr ptr float)
+@ stdcall D3DRMQuaternionMultiply(ptr ptr ptr)
+@ stdcall D3DRMQuaternionSlerp(ptr ptr ptr float)
+@ stdcall D3DRMVectorAdd(ptr ptr ptr)
+@ stdcall D3DRMVectorCrossProduct(ptr ptr ptr)
+@ stdcall D3DRMVectorDotProduct(ptr ptr)
+@ stdcall D3DRMVectorModulus(ptr)
+@ stdcall D3DRMVectorNormalize(ptr)
+@ stdcall D3DRMVectorRandom(ptr)
+@ stdcall D3DRMVectorReflect(ptr ptr ptr)
+@ stdcall D3DRMVectorRotate(ptr ptr ptr float)
+@ stdcall D3DRMVectorScale(ptr ptr float)
+@ stdcall D3DRMVectorSubtract(ptr ptr ptr)
+@ stdcall Direct3DRMCreate(ptr)
+@ stub DllCanUnloadNow
+@ stub DllGetClassObject
diff --git a/reactos/dll/directx/wine/d3drm/d3drm_main.c b/reactos/dll/directx/wine/d3drm/d3drm_main.c
new file mode 100644 (file)
index 0000000..888d866
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2004 Ivan Leo Puoti
+ * Copyright 2010 Christian Costa
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+/***********************************************************************
+ *             DllMain  (D3DRM.@)
+ */
+BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved)
+{
+    switch(reason)
+    {
+    case DLL_WINE_PREATTACH:
+        return FALSE;  /* prefer native version */
+    case DLL_PROCESS_ATTACH:
+        DisableThreadLibraryCalls( inst );
+        break;
+    }
+    return TRUE;
+}
diff --git a/reactos/dll/directx/wine/d3drm/d3drm_private.h b/reactos/dll/directx/wine/d3drm/d3drm_private.h
new file mode 100644 (file)
index 0000000..777fe68
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *      Direct3DRM private interfaces (D3DRM.DLL)
+ *
+ * Copyright 2010 Christian Costa
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __D3DRM_PRIVATE_INCLUDED__
+#define __D3DRM_PRIVATE_INCLUDED__
+
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include <windef.h>
+#include <winbase.h>
+#include <wingdi.h>
+#include <d3drm.h>
+#include <dxfile.h>
+#include <rmxfguid.h>
+
+#include <wine/debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(d3drm);
+
+HRESULT Direct3DRMDevice_create(REFIID riid, IUnknown** ppObj) DECLSPEC_HIDDEN;
+HRESULT Direct3DRMFace_create(REFIID riid, IUnknown** ret_iface) DECLSPEC_HIDDEN;
+HRESULT Direct3DRMFrame_create(REFIID riid, IUnknown* parent_frame, IUnknown** ret_iface) DECLSPEC_HIDDEN;
+HRESULT Direct3DRMLight_create(IUnknown** ppObj) DECLSPEC_HIDDEN;
+HRESULT Direct3DRMMesh_create(IDirect3DRMMesh** obj) DECLSPEC_HIDDEN;
+HRESULT Direct3DRMMeshBuilder_create(REFIID riid, IUnknown** ppObj) DECLSPEC_HIDDEN;
+HRESULT Direct3DRMViewport_create(REFIID riid, IUnknown** ppObj) DECLSPEC_HIDDEN;
+HRESULT Direct3DRMMaterial_create(IDirect3DRMMaterial2** ret_iface) DECLSPEC_HIDDEN;
+HRESULT Direct3DRMTexture_create(REFIID riid, IUnknown** ret_iface) DECLSPEC_HIDDEN;
+
+HRESULT load_mesh_data(IDirect3DRMMeshBuilder3 *iface, IDirectXFileData *data,
+                       D3DRMLOADTEXTURECALLBACK load_texture_proc, void *arg) DECLSPEC_HIDDEN;
+
+struct d3drm_file_header
+{
+    WORD major;
+    WORD minor;
+    DWORD flags;
+};
+
+extern char templates[];
+
+#endif /* __D3DRM_PRIVATE_INCLUDED__ */
diff --git a/reactos/dll/directx/wine/d3drm/device.c b/reactos/dll/directx/wine/d3drm/device.c
new file mode 100644 (file)
index 0000000..9b01575
--- /dev/null
@@ -0,0 +1,984 @@
+/*
+ * Implementation of IDirect3DRMDevice Interface
+ *
+ * Copyright 2011, 2012 André Hentschel
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+#include <d3drmwin.h>
+
+struct d3drm_device
+{
+    IDirect3DRMDevice2 IDirect3DRMDevice2_iface;
+    IDirect3DRMDevice3 IDirect3DRMDevice3_iface;
+    IDirect3DRMWinDevice IDirect3DRMWinDevice_iface;
+    LONG ref;
+    BOOL dither;
+    D3DRMRENDERQUALITY quality;
+    DWORD rendermode;
+    DWORD height;
+    DWORD width;
+};
+
+static inline struct d3drm_device *impl_from_IDirect3DRMDevice2(IDirect3DRMDevice2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_device, IDirect3DRMDevice2_iface);
+}
+
+static inline struct d3drm_device *impl_from_IDirect3DRMDevice3(IDirect3DRMDevice3 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_device, IDirect3DRMDevice3_iface);
+}
+
+static inline struct d3drm_device *impl_from_IDirect3DRMWinDevice(IDirect3DRMWinDevice *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_device, IDirect3DRMWinDevice_iface);
+}
+
+static HRESULT WINAPI d3drm_device2_QueryInterface(IDirect3DRMDevice2 *iface, REFIID riid, void **out)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMDevice2)
+            || IsEqualGUID(riid, &IID_IDirect3DRMDevice)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *out = &device->IDirect3DRMDevice2_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRMDevice3))
+    {
+        *out = &device->IDirect3DRMDevice3_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRMWinDevice))
+    {
+        *out = &device->IDirect3DRMWinDevice_iface;
+    }
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI d3drm_device2_AddRef(IDirect3DRMDevice2 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+    ULONG refcount = InterlockedIncrement(&device->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_device2_Release(IDirect3DRMDevice2 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+    ULONG refcount = InterlockedDecrement(&device->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+        HeapFree(GetProcessHeap(), 0, device);
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_device2_Clone(IDirect3DRMDevice2 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_AddDestroyCallback(IDirect3DRMDevice2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_DeleteDestroyCallback(IDirect3DRMDevice2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_SetAppData(IDirect3DRMDevice2 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device2_GetAppData(IDirect3DRMDevice2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_device2_SetName(IDirect3DRMDevice2 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_GetName(IDirect3DRMDevice2 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_GetClassName(IDirect3DRMDevice2 *iface, DWORD *size, char *name)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    return IDirect3DRMDevice3_GetClassName(&device->IDirect3DRMDevice3_iface, size, name);
+}
+
+static HRESULT WINAPI d3drm_device2_Init(IDirect3DRMDevice2 *iface, ULONG width, ULONG height)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p, width %u, height %u.\n", iface, width, height);
+
+    return IDirect3DRMDevice3_Init(&device->IDirect3DRMDevice3_iface, width, height);
+}
+
+static HRESULT WINAPI d3drm_device2_InitFromD3D(IDirect3DRMDevice2 *iface,
+        IDirect3D *d3d, IDirect3DDevice *d3d_device)
+{
+    FIXME("iface %p, d3d %p, d3d_device %p stub!\n", iface, d3d, d3d_device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_InitFromClipper(IDirect3DRMDevice2 *iface,
+        IDirectDrawClipper *clipper, GUID *guid, int width, int height)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p, clipper %p, guid %s, width %d, height %d.\n",
+            iface, clipper, debugstr_guid(guid), width, height);
+
+    return IDirect3DRMDevice3_InitFromClipper(&device->IDirect3DRMDevice3_iface,
+            clipper, guid, width, height);
+}
+
+static HRESULT WINAPI d3drm_device2_Update(IDirect3DRMDevice2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_device2_AddUpdateCallback(IDirect3DRMDevice2 *iface,
+        D3DRMUPDATECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_DeleteUpdateCallback(IDirect3DRMDevice2 *iface,
+        D3DRMUPDATECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_SetBufferCount(IDirect3DRMDevice2 *iface, DWORD count)
+{
+    FIXME("iface %p, count %u.\n", iface, count);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device2_GetBufferCount(IDirect3DRMDevice2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_SetDither(IDirect3DRMDevice2 *iface, BOOL enable)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p, enabled %#x.\n", iface, enable);
+
+    return IDirect3DRMDevice3_SetDither(&device->IDirect3DRMDevice3_iface, enable);
+}
+
+static HRESULT WINAPI d3drm_device2_SetShades(IDirect3DRMDevice2 *iface, DWORD count)
+{
+    FIXME("iface %p, count %u stub!\n", iface, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_SetQuality(IDirect3DRMDevice2 *iface, D3DRMRENDERQUALITY quality)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p, quality %u.\n", iface, quality);
+
+    return IDirect3DRMDevice3_SetQuality(&device->IDirect3DRMDevice3_iface, quality);
+}
+
+static HRESULT WINAPI d3drm_device2_SetTextureQuality(IDirect3DRMDevice2 *iface, D3DRMTEXTUREQUALITY quality)
+{
+    FIXME("iface %p, quality %u stub!\n", iface, quality);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_GetViewports(IDirect3DRMDevice2 *iface, IDirect3DRMViewportArray **array)
+{
+    FIXME("iface %p, array %p stub!\n", iface, array);
+
+    return E_NOTIMPL;
+}
+
+static BOOL WINAPI d3drm_device2_GetDither(IDirect3DRMDevice2 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMDevice3_GetDither(&device->IDirect3DRMDevice3_iface);
+}
+
+static DWORD WINAPI d3drm_device2_GetShades(IDirect3DRMDevice2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device2_GetHeight(IDirect3DRMDevice2 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMDevice3_GetHeight(&device->IDirect3DRMDevice3_iface);
+}
+
+static DWORD WINAPI d3drm_device2_GetWidth(IDirect3DRMDevice2 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMDevice3_GetWidth(&device->IDirect3DRMDevice3_iface);
+}
+
+static DWORD WINAPI d3drm_device2_GetTrianglesDrawn(IDirect3DRMDevice2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device2_GetWireframeOptions(IDirect3DRMDevice2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMRENDERQUALITY WINAPI d3drm_device2_GetQuality(IDirect3DRMDevice2 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMDevice3_GetQuality(&device->IDirect3DRMDevice3_iface);
+}
+
+static D3DCOLORMODEL WINAPI d3drm_device2_GetColorModel(IDirect3DRMDevice2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMTEXTUREQUALITY WINAPI d3drm_device2_GetTextureQuality(IDirect3DRMDevice2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_GetDirect3DDevice(IDirect3DRMDevice2 *iface, IDirect3DDevice **d3d_device)
+{
+    FIXME("iface %p, d3d_device %p stub!\n", iface, d3d_device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_InitFromD3D2(IDirect3DRMDevice2 *iface,
+        IDirect3D2 *d3d, IDirect3DDevice2 *d3d_device)
+{
+    FIXME("iface %p, d3d %p, d3d_device %p stub!\n", iface, d3d, d3d_device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_InitFromSurface(IDirect3DRMDevice2 *iface,
+        GUID *guid, IDirectDraw *ddraw, IDirectDrawSurface *backbuffer)
+{
+    FIXME("iface %p, guid %s, ddraw %p, backbuffer %p stub!\n",
+            iface, debugstr_guid(guid), ddraw, backbuffer);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device2_SetRenderMode(IDirect3DRMDevice2 *iface, DWORD flags)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p, flags %#x.\n", iface, flags);
+
+    return IDirect3DRMDevice3_SetRenderMode(&device->IDirect3DRMDevice3_iface, flags);
+}
+
+static DWORD WINAPI d3drm_device2_GetRenderMode(IDirect3DRMDevice2 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMDevice3_GetRenderMode(&device->IDirect3DRMDevice3_iface);
+}
+
+static HRESULT WINAPI d3drm_device2_GetDirect3DDevice2(IDirect3DRMDevice2 *iface, IDirect3DDevice2 **d3d_device)
+{
+    FIXME("iface %p, d3d_device %p stub!\n", iface, d3d_device);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMDevice2Vtbl d3drm_device2_vtbl =
+{
+    d3drm_device2_QueryInterface,
+    d3drm_device2_AddRef,
+    d3drm_device2_Release,
+    d3drm_device2_Clone,
+    d3drm_device2_AddDestroyCallback,
+    d3drm_device2_DeleteDestroyCallback,
+    d3drm_device2_SetAppData,
+    d3drm_device2_GetAppData,
+    d3drm_device2_SetName,
+    d3drm_device2_GetName,
+    d3drm_device2_GetClassName,
+    d3drm_device2_Init,
+    d3drm_device2_InitFromD3D,
+    d3drm_device2_InitFromClipper,
+    d3drm_device2_Update,
+    d3drm_device2_AddUpdateCallback,
+    d3drm_device2_DeleteUpdateCallback,
+    d3drm_device2_SetBufferCount,
+    d3drm_device2_GetBufferCount,
+    d3drm_device2_SetDither,
+    d3drm_device2_SetShades,
+    d3drm_device2_SetQuality,
+    d3drm_device2_SetTextureQuality,
+    d3drm_device2_GetViewports,
+    d3drm_device2_GetDither,
+    d3drm_device2_GetShades,
+    d3drm_device2_GetHeight,
+    d3drm_device2_GetWidth,
+    d3drm_device2_GetTrianglesDrawn,
+    d3drm_device2_GetWireframeOptions,
+    d3drm_device2_GetQuality,
+    d3drm_device2_GetColorModel,
+    d3drm_device2_GetTextureQuality,
+    d3drm_device2_GetDirect3DDevice,
+    d3drm_device2_InitFromD3D2,
+    d3drm_device2_InitFromSurface,
+    d3drm_device2_SetRenderMode,
+    d3drm_device2_GetRenderMode,
+    d3drm_device2_GetDirect3DDevice2,
+};
+
+static HRESULT WINAPI d3drm_device3_QueryInterface(IDirect3DRMDevice3 *iface, REFIID riid, void **out)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    return d3drm_device2_QueryInterface(&device->IDirect3DRMDevice2_iface, riid, out);
+}
+
+static ULONG WINAPI d3drm_device3_AddRef(IDirect3DRMDevice3 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    return d3drm_device2_AddRef(&device->IDirect3DRMDevice2_iface);
+}
+
+static ULONG WINAPI d3drm_device3_Release(IDirect3DRMDevice3 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    return d3drm_device2_Release(&device->IDirect3DRMDevice2_iface);
+}
+
+static HRESULT WINAPI d3drm_device3_Clone(IDirect3DRMDevice3 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_AddDestroyCallback(IDirect3DRMDevice3 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_DeleteDestroyCallback(IDirect3DRMDevice3 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_SetAppData(IDirect3DRMDevice3 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device3_GetAppData(IDirect3DRMDevice3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_device3_SetName(IDirect3DRMDevice3 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_GetName(IDirect3DRMDevice3 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_GetClassName(IDirect3DRMDevice3 *iface, DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Device") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Device");
+    *size = sizeof("Device");
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_device3_Init(IDirect3DRMDevice3 *iface, ULONG width, ULONG height)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    FIXME("iface %p, width %u, height %u stub!\n", iface, width, height);
+
+    device->height = height;
+    device->width = width;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_device3_InitFromD3D(IDirect3DRMDevice3 *iface,
+        IDirect3D *d3d, IDirect3DDevice *d3d_device)
+{
+    FIXME("iface %p, d3d %p, d3d_device %p stub!\n", iface, d3d, d3d_device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_InitFromClipper(IDirect3DRMDevice3 *iface,
+        IDirectDrawClipper *clipper, GUID *guid, int width, int height)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    FIXME("iface %p, clipper %p, guid %s, width %d, height %d stub!\n",
+            iface, clipper, debugstr_guid(guid), width, height);
+
+    device->height = height;
+    device->width = width;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_device3_Update(IDirect3DRMDevice3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_device3_AddUpdateCallback(IDirect3DRMDevice3 *iface,
+        D3DRMUPDATECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_DeleteUpdateCallback(IDirect3DRMDevice3 *iface,
+        D3DRMUPDATECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_SetBufferCount(IDirect3DRMDevice3 *iface, DWORD count)
+{
+    FIXME("iface %p, count %u stub!\n", iface, count);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device3_GetBufferCount(IDirect3DRMDevice3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_SetDither(IDirect3DRMDevice3 *iface, BOOL enable)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    TRACE("iface %p, enable %#x.\n", iface, enable);
+
+    device->dither = enable;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_device3_SetShades(IDirect3DRMDevice3 *iface, DWORD count)
+{
+    FIXME("iface %p, count %u stub!\n", iface, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_SetQuality(IDirect3DRMDevice3 *iface, D3DRMRENDERQUALITY quality)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    TRACE("iface %p, quality %u.\n", iface, quality);
+
+    device->quality = quality;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_device3_SetTextureQuality(IDirect3DRMDevice3 *iface, D3DRMTEXTUREQUALITY quality)
+{
+    FIXME("iface %p, quality %u stub!\n", iface, quality);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_GetViewports(IDirect3DRMDevice3 *iface, IDirect3DRMViewportArray **array)
+{
+    FIXME("iface %p, array %p stub!\n", iface, array);
+
+    return E_NOTIMPL;
+}
+
+static BOOL WINAPI d3drm_device3_GetDither(IDirect3DRMDevice3 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return device->dither;
+}
+
+static DWORD WINAPI d3drm_device3_GetShades(IDirect3DRMDevice3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device3_GetHeight(IDirect3DRMDevice3 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return device->height;
+}
+
+static DWORD WINAPI d3drm_device3_GetWidth(IDirect3DRMDevice3 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return device->width;
+}
+
+static DWORD WINAPI d3drm_device3_GetTrianglesDrawn(IDirect3DRMDevice3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device3_GetWireframeOptions(IDirect3DRMDevice3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMRENDERQUALITY WINAPI d3drm_device3_GetQuality(IDirect3DRMDevice3 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return device->quality;
+}
+
+static D3DCOLORMODEL WINAPI d3drm_device3_GetColorModel(IDirect3DRMDevice3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMTEXTUREQUALITY WINAPI d3drm_device3_GetTextureQuality(IDirect3DRMDevice3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_GetDirect3DDevice(IDirect3DRMDevice3 *iface, IDirect3DDevice **d3d_device)
+{
+    FIXME("iface %p, d3d_device %p stub!\n", iface, d3d_device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_InitFromD3D2(IDirect3DRMDevice3 *iface,
+        IDirect3D2 *d3d, IDirect3DDevice2 *d3d_device)
+{
+    FIXME("iface %p, d3d %p, d3d_device %p stub!\n", iface, d3d, d3d_device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_InitFromSurface(IDirect3DRMDevice3 *iface,
+        GUID *guid, IDirectDraw *ddraw, IDirectDrawSurface *backbuffer)
+{
+    FIXME("iface %p, guid %s, ddraw %p, backbuffer %p stub!\n",
+            iface, debugstr_guid(guid), ddraw, backbuffer);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_SetRenderMode(IDirect3DRMDevice3 *iface, DWORD flags)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    TRACE("iface %p, flags %#x.\n", iface, flags);
+
+    device->rendermode = flags;
+
+    return D3DRM_OK;
+}
+
+static DWORD WINAPI d3drm_device3_GetRenderMode(IDirect3DRMDevice3 *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMDevice3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return device->rendermode;
+}
+
+static HRESULT WINAPI d3drm_device3_GetDirect3DDevice2(IDirect3DRMDevice3 *iface, IDirect3DDevice2 **d3d_device)
+{
+    FIXME("iface %p, d3d_device %p stub!\n", iface, d3d_device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_FindPreferredTextureFormat(IDirect3DRMDevice3 *iface,
+        DWORD bitdepths, DWORD flags, DDPIXELFORMAT *pf)
+{
+    FIXME("iface %p, bitdepths %u, flags %#x, pf %p stub!\n", iface, bitdepths, flags, pf);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_RenderStateChange(IDirect3DRMDevice3 *iface,
+        D3DRENDERSTATETYPE state, DWORD value, DWORD flags)
+{
+    FIXME("iface %p, state %#x, value %#x, flags %#x stub!\n", iface, state, value, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_LightStateChange(IDirect3DRMDevice3 *iface,
+        D3DLIGHTSTATETYPE state, DWORD value, DWORD flags)
+{
+    FIXME("iface %p, state %#x, value %#x, flags %#x stub!\n", iface, state, value, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_GetStateChangeOptions(IDirect3DRMDevice3 *iface,
+        DWORD state_class, DWORD state_idx, DWORD *flags)
+{
+    FIXME("iface %p, state_class %#x, state_idx %#x, flags %p stub!\n",
+            iface, state_class, state_idx, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device3_SetStateChangeOptions(IDirect3DRMDevice3 *iface,
+        DWORD state_class, DWORD state_idx, DWORD flags)
+{
+    FIXME("iface %p, state_class %#x, state_idx %#x, flags %#x stub!\n",
+            iface, state_class, state_idx, flags);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMDevice3Vtbl d3drm_device3_vtbl =
+{
+    d3drm_device3_QueryInterface,
+    d3drm_device3_AddRef,
+    d3drm_device3_Release,
+    d3drm_device3_Clone,
+    d3drm_device3_AddDestroyCallback,
+    d3drm_device3_DeleteDestroyCallback,
+    d3drm_device3_SetAppData,
+    d3drm_device3_GetAppData,
+    d3drm_device3_SetName,
+    d3drm_device3_GetName,
+    d3drm_device3_GetClassName,
+    d3drm_device3_Init,
+    d3drm_device3_InitFromD3D,
+    d3drm_device3_InitFromClipper,
+    d3drm_device3_Update,
+    d3drm_device3_AddUpdateCallback,
+    d3drm_device3_DeleteUpdateCallback,
+    d3drm_device3_SetBufferCount,
+    d3drm_device3_GetBufferCount,
+    d3drm_device3_SetDither,
+    d3drm_device3_SetShades,
+    d3drm_device3_SetQuality,
+    d3drm_device3_SetTextureQuality,
+    d3drm_device3_GetViewports,
+    d3drm_device3_GetDither,
+    d3drm_device3_GetShades,
+    d3drm_device3_GetHeight,
+    d3drm_device3_GetWidth,
+    d3drm_device3_GetTrianglesDrawn,
+    d3drm_device3_GetWireframeOptions,
+    d3drm_device3_GetQuality,
+    d3drm_device3_GetColorModel,
+    d3drm_device3_GetTextureQuality,
+    d3drm_device3_GetDirect3DDevice,
+    d3drm_device3_InitFromD3D2,
+    d3drm_device3_InitFromSurface,
+    d3drm_device3_SetRenderMode,
+    d3drm_device3_GetRenderMode,
+    d3drm_device3_GetDirect3DDevice2,
+    d3drm_device3_FindPreferredTextureFormat,
+    d3drm_device3_RenderStateChange,
+    d3drm_device3_LightStateChange,
+    d3drm_device3_GetStateChangeOptions,
+    d3drm_device3_SetStateChangeOptions,
+};
+
+static HRESULT WINAPI d3drm_device_win_QueryInterface(IDirect3DRMWinDevice *iface, REFIID riid, void **out)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMWinDevice(iface);
+
+    return d3drm_device2_QueryInterface(&device->IDirect3DRMDevice2_iface, riid, out);
+}
+
+static ULONG WINAPI d3drm_device_win_AddRef(IDirect3DRMWinDevice *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMWinDevice(iface);
+
+    return d3drm_device2_AddRef(&device->IDirect3DRMDevice2_iface);
+}
+
+static ULONG WINAPI d3drm_device_win_Release(IDirect3DRMWinDevice *iface)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMWinDevice(iface);
+
+    return d3drm_device2_Release(&device->IDirect3DRMDevice2_iface);
+}
+
+static HRESULT WINAPI d3drm_device_win_Clone(IDirect3DRMWinDevice *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device_win_AddDestroyCallback(IDirect3DRMWinDevice *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device_win_DeleteDestroyCallback(IDirect3DRMWinDevice *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device_win_SetAppData(IDirect3DRMWinDevice *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_device_win_GetAppData(IDirect3DRMWinDevice *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_device_win_SetName(IDirect3DRMWinDevice *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device_win_GetName(IDirect3DRMWinDevice *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_device_win_GetClassName(IDirect3DRMWinDevice *iface, DWORD *size, char *name)
+{
+    struct d3drm_device *device = impl_from_IDirect3DRMWinDevice(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    return IDirect3DRMDevice3_GetClassName(&device->IDirect3DRMDevice3_iface, size, name);
+}
+
+static HRESULT WINAPI d3drm_device_win_HandlePaint(IDirect3DRMWinDevice *iface, HDC dc)
+{
+    FIXME("iface %p, dc %p stub!\n", iface, dc);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_device_win_HandleActivate(IDirect3DRMWinDevice *iface, WORD wparam)
+{
+    FIXME("iface %p, wparam %#x stub!\n", iface, wparam);
+
+    return D3DRM_OK;
+}
+
+static const struct IDirect3DRMWinDeviceVtbl d3drm_device_win_vtbl =
+{
+    d3drm_device_win_QueryInterface,
+    d3drm_device_win_AddRef,
+    d3drm_device_win_Release,
+    d3drm_device_win_Clone,
+    d3drm_device_win_AddDestroyCallback,
+    d3drm_device_win_DeleteDestroyCallback,
+    d3drm_device_win_SetAppData,
+    d3drm_device_win_GetAppData,
+    d3drm_device_win_SetName,
+    d3drm_device_win_GetName,
+    d3drm_device_win_GetClassName,
+    d3drm_device_win_HandlePaint,
+    d3drm_device_win_HandleActivate,
+};
+
+HRESULT Direct3DRMDevice_create(REFIID riid, IUnknown **out)
+{
+    struct d3drm_device *object;
+
+    TRACE("riid %s, out %p.\n", debugstr_guid(riid), out);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMDevice2_iface.lpVtbl = &d3drm_device2_vtbl;
+    object->IDirect3DRMDevice3_iface.lpVtbl = &d3drm_device3_vtbl;
+    object->IDirect3DRMWinDevice_iface.lpVtbl = &d3drm_device_win_vtbl;
+    object->ref = 1;
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMDevice3))
+        *out = (IUnknown*)&object->IDirect3DRMDevice3_iface;
+    else
+        *out = (IUnknown*)&object->IDirect3DRMDevice2_iface;
+
+    return S_OK;
+}
diff --git a/reactos/dll/directx/wine/d3drm/face.c b/reactos/dll/directx/wine/d3drm/face.c
new file mode 100644 (file)
index 0000000..5cb3734
--- /dev/null
@@ -0,0 +1,606 @@
+/*
+ * Implementation of IDirect3DRMFace Interface
+ *
+ * Copyright 2013 André Hentschel
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+struct d3drm_face
+{
+    IDirect3DRMFace IDirect3DRMFace_iface;
+    IDirect3DRMFace2 IDirect3DRMFace2_iface;
+    LONG ref;
+};
+
+static inline struct d3drm_face *impl_from_IDirect3DRMFace(IDirect3DRMFace *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_face, IDirect3DRMFace_iface);
+}
+
+static inline struct d3drm_face *impl_from_IDirect3DRMFace2(IDirect3DRMFace2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_face, IDirect3DRMFace2_iface);
+}
+
+static HRESULT WINAPI d3drm_face1_QueryInterface(IDirect3DRMFace *iface, REFIID riid, void **out)
+{
+    struct d3drm_face *face = impl_from_IDirect3DRMFace(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMFace)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *out = &face->IDirect3DRMFace_iface;
+    }
+    else if(IsEqualGUID(riid, &IID_IDirect3DRMFace2))
+    {
+        *out = &face->IDirect3DRMFace2_iface;
+    }
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI d3drm_face1_AddRef(IDirect3DRMFace *iface)
+{
+    struct d3drm_face *face = impl_from_IDirect3DRMFace(iface);
+    ULONG refcount = InterlockedIncrement(&face->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_face1_Release(IDirect3DRMFace *iface)
+{
+    struct d3drm_face *face = impl_from_IDirect3DRMFace(iface);
+    ULONG refcount = InterlockedDecrement(&face->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+        HeapFree(GetProcessHeap(), 0, face);
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_face1_Clone(IDirect3DRMFace *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_AddDestroyCallback(IDirect3DRMFace *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_DeleteDestroyCallback(IDirect3DRMFace *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_SetAppData(IDirect3DRMFace *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_face1_GetAppData(IDirect3DRMFace *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_face1_SetName(IDirect3DRMFace *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetName(IDirect3DRMFace *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetClassName(IDirect3DRMFace *iface, DWORD *size, char *name)
+{
+    struct d3drm_face *face = impl_from_IDirect3DRMFace(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    return IDirect3DRMFace2_GetClassName(&face->IDirect3DRMFace2_iface, size, name);
+}
+
+static HRESULT WINAPI d3drm_face1_AddVertex(IDirect3DRMFace *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, x %.8e, y %.8e, z %.8e stub!\n", iface, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_AddVertexAndNormalIndexed(IDirect3DRMFace *iface,
+        DWORD vertex, DWORD normal)
+{
+    FIXME("iface %p, vertex %u, normal %u stub!\n", iface, vertex, normal);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_SetColorRGB(IDirect3DRMFace *iface,
+        D3DVALUE r, D3DVALUE g, D3DVALUE b)
+{
+    FIXME("iface %p, r %.8e, g %.8e, b %.8e stub!\n", iface, r, g, b);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_SetColor(IDirect3DRMFace *iface, D3DCOLOR color)
+{
+    FIXME("iface %p, color 0x%08x stub!\n", iface, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_SetTexture(IDirect3DRMFace *iface, IDirect3DRMTexture *texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_SetTextureCoordinates(IDirect3DRMFace *iface,
+        DWORD vertex, D3DVALUE u, D3DVALUE v)
+{
+    FIXME("iface %p, vertex %u, u %.8e, v %.8e stub!\n", iface, vertex, u, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_SetMaterial(IDirect3DRMFace *iface, IDirect3DRMMaterial *material)
+{
+    FIXME("iface %p, material %p stub!\n", iface, material);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_SetTextureTopology(IDirect3DRMFace *iface, BOOL wrap_u, BOOL wrap_v)
+{
+    FIXME("iface %p, wrap_u %#x, wrap_v %#x stub!\n", iface, wrap_u, wrap_v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetVertex(IDirect3DRMFace *iface,
+        DWORD index, D3DVECTOR *vertex, D3DVECTOR *normal)
+{
+    FIXME("iface %p, index %u, vertex %p, normal %p stub!\n", iface, index, vertex, normal);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetVertices(IDirect3DRMFace *iface,
+        DWORD *vertex_count, D3DVECTOR *coords, D3DVECTOR *normals)
+{
+    FIXME("iface %p, vertex_count %p, coords %p, normals %p stub!\n",
+            iface, vertex_count, coords, normals);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetTextureCoordinates(IDirect3DRMFace *iface,
+        DWORD vertex, D3DVALUE *u, D3DVALUE *v)
+{
+    FIXME("iface %p, vertex %u, u %p, v %p stub!\n", iface, vertex, u, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetTextureTopology(IDirect3DRMFace *iface, BOOL *wrap_u, BOOL *wrap_v)
+{
+    FIXME("iface %p, wrap_u %p, wrap_v %p stub!\n", iface, wrap_u, wrap_v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetNormal(IDirect3DRMFace *iface, D3DVECTOR *normal)
+{
+    FIXME("iface %p, normal %p stub!\n", iface, normal);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetTexture(IDirect3DRMFace *iface, IDirect3DRMTexture **texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face1_GetMaterial(IDirect3DRMFace *iface, IDirect3DRMMaterial **material)
+{
+    FIXME("iface %p, material %p stub!\n", iface, material);
+
+    return E_NOTIMPL;
+}
+
+static int WINAPI d3drm_face1_GetVertexCount(IDirect3DRMFace *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static int WINAPI d3drm_face1_GetVertexIndex(IDirect3DRMFace *iface, DWORD which)
+{
+    FIXME("iface %p, which %u stub!\n", iface, which);
+
+    return 0;
+}
+
+static int WINAPI d3drm_face1_GetTextureCoordinateIndex(IDirect3DRMFace *iface, DWORD which)
+{
+    FIXME("iface %p, which %u stub!\n", iface, which);
+
+    return 0;
+}
+
+static D3DCOLOR WINAPI d3drm_face1_GetColor(IDirect3DRMFace *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static const struct IDirect3DRMFaceVtbl d3drm_face1_vtbl =
+{
+    d3drm_face1_QueryInterface,
+    d3drm_face1_AddRef,
+    d3drm_face1_Release,
+    d3drm_face1_Clone,
+    d3drm_face1_AddDestroyCallback,
+    d3drm_face1_DeleteDestroyCallback,
+    d3drm_face1_SetAppData,
+    d3drm_face1_GetAppData,
+    d3drm_face1_SetName,
+    d3drm_face1_GetName,
+    d3drm_face1_GetClassName,
+    d3drm_face1_AddVertex,
+    d3drm_face1_AddVertexAndNormalIndexed,
+    d3drm_face1_SetColorRGB,
+    d3drm_face1_SetColor,
+    d3drm_face1_SetTexture,
+    d3drm_face1_SetTextureCoordinates,
+    d3drm_face1_SetMaterial,
+    d3drm_face1_SetTextureTopology,
+    d3drm_face1_GetVertex,
+    d3drm_face1_GetVertices,
+    d3drm_face1_GetTextureCoordinates,
+    d3drm_face1_GetTextureTopology,
+    d3drm_face1_GetNormal,
+    d3drm_face1_GetTexture,
+    d3drm_face1_GetMaterial,
+    d3drm_face1_GetVertexCount,
+    d3drm_face1_GetVertexIndex,
+    d3drm_face1_GetTextureCoordinateIndex,
+    d3drm_face1_GetColor,
+};
+
+static HRESULT WINAPI d3drm_face2_QueryInterface(IDirect3DRMFace2 *iface, REFIID riid, void **out)
+{
+    struct d3drm_face *face = impl_from_IDirect3DRMFace2(iface);
+
+    return d3drm_face1_QueryInterface(&face->IDirect3DRMFace_iface, riid, out);
+}
+
+static ULONG WINAPI d3drm_face2_AddRef(IDirect3DRMFace2 *iface)
+{
+    struct d3drm_face *face = impl_from_IDirect3DRMFace2(iface);
+
+    return d3drm_face1_AddRef(&face->IDirect3DRMFace_iface);
+}
+
+static ULONG WINAPI d3drm_face2_Release(IDirect3DRMFace2 *iface)
+{
+    struct d3drm_face *face = impl_from_IDirect3DRMFace2(iface);
+
+    return d3drm_face1_Release(&face->IDirect3DRMFace_iface);
+}
+
+static HRESULT WINAPI d3drm_face2_Clone(IDirect3DRMFace2 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_AddDestroyCallback(IDirect3DRMFace2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_DeleteDestroyCallback(IDirect3DRMFace2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_SetAppData(IDirect3DRMFace2 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_face2_GetAppData(IDirect3DRMFace2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_face2_SetName(IDirect3DRMFace2 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetName(IDirect3DRMFace2 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetClassName(IDirect3DRMFace2 *iface, DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Face") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Face");
+    *size = sizeof("Face");
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_face2_AddVertex(IDirect3DRMFace2 *iface, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, x %.8e, y %.8e, z %.8e stub!\n", iface, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_AddVertexAndNormalIndexed(IDirect3DRMFace2 *iface,
+        DWORD vertex, DWORD normal)
+{
+    FIXME("iface %p, vertex %u, normal %u stub!\n", iface, vertex, normal);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_SetColorRGB(IDirect3DRMFace2 *iface, D3DVALUE r, D3DVALUE g, D3DVALUE b)
+{
+    FIXME("iface %p, r %.8e, g %.8e, b %.8e stub!\n", iface, r, g, b);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_SetColor(IDirect3DRMFace2 *iface, D3DCOLOR color)
+{
+    FIXME("iface %p, color 0x%08x stub!\n", iface, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_SetTexture(IDirect3DRMFace2 *iface, IDirect3DRMTexture3 *texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_SetTextureCoordinates(IDirect3DRMFace2 *iface,
+        DWORD vertex, D3DVALUE u, D3DVALUE v)
+{
+    FIXME("iface %p, vertex %u, u %.8e, v %.8e stub!\n", iface, vertex, u, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_SetMaterial(IDirect3DRMFace2 *iface, IDirect3DRMMaterial2 *material)
+{
+    FIXME("iface %p, material %p stub!\n", iface, material);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_SetTextureTopology(IDirect3DRMFace2 *iface, BOOL wrap_u, BOOL wrap_v)
+{
+    FIXME("iface %p, wrap_u %#x, wrap_v %#x stub!\n", iface, wrap_u, wrap_v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetVertex(IDirect3DRMFace2 *iface,
+        DWORD index, D3DVECTOR *vertex, D3DVECTOR *normal)
+{
+    FIXME("iface %p, index %u, vertex %p, normal %p stub!\n", iface, index, vertex, normal);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetVertices(IDirect3DRMFace2 *iface,
+        DWORD *vertex_count, D3DVECTOR *coords, D3DVECTOR *normals)
+{
+    FIXME("iface %p, vertex_count %p, coords %p, normals %p stub!\n",
+            iface, vertex_count, coords, normals);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetTextureCoordinates(IDirect3DRMFace2 *iface,
+        DWORD vertex, D3DVALUE *u, D3DVALUE *v)
+{
+    FIXME("iface %p, vertex %u, u %p, v %p stub!\n", iface, vertex, u, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetTextureTopology(IDirect3DRMFace2 *iface, BOOL *wrap_u, BOOL *wrap_v)
+{
+    FIXME("iface %p, wrap_u %p, wrap_v %p stub!\n", iface, wrap_u, wrap_v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetNormal(IDirect3DRMFace2 *iface, D3DVECTOR *normal)
+{
+    FIXME("iface %p, normal %p stub!\n", iface, normal);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetTexture(IDirect3DRMFace2 *iface, IDirect3DRMTexture3 **texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_face2_GetMaterial(IDirect3DRMFace2 *iface, IDirect3DRMMaterial2 **material)
+{
+    FIXME("iface %p, material %p stub!\n", iface, material);
+
+    return E_NOTIMPL;
+}
+
+static int WINAPI d3drm_face2_GetVertexCount(IDirect3DRMFace2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static int WINAPI d3drm_face2_GetVertexIndex(IDirect3DRMFace2 *iface, DWORD which)
+{
+    FIXME("iface %p, which %u stub!\n", iface, which);
+
+    return 0;
+}
+
+static int WINAPI d3drm_face2_GetTextureCoordinateIndex(IDirect3DRMFace2 *iface, DWORD which)
+{
+    FIXME("iface %p, which %u stub!\n", iface, which);
+
+    return 0;
+}
+
+static D3DCOLOR WINAPI d3drm_face2_GetColor(IDirect3DRMFace2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static const struct IDirect3DRMFace2Vtbl d3drm_face2_vtbl =
+{
+    d3drm_face2_QueryInterface,
+    d3drm_face2_AddRef,
+    d3drm_face2_Release,
+    d3drm_face2_Clone,
+    d3drm_face2_AddDestroyCallback,
+    d3drm_face2_DeleteDestroyCallback,
+    d3drm_face2_SetAppData,
+    d3drm_face2_GetAppData,
+    d3drm_face2_SetName,
+    d3drm_face2_GetName,
+    d3drm_face2_GetClassName,
+    d3drm_face2_AddVertex,
+    d3drm_face2_AddVertexAndNormalIndexed,
+    d3drm_face2_SetColorRGB,
+    d3drm_face2_SetColor,
+    d3drm_face2_SetTexture,
+    d3drm_face2_SetTextureCoordinates,
+    d3drm_face2_SetMaterial,
+    d3drm_face2_SetTextureTopology,
+    d3drm_face2_GetVertex,
+    d3drm_face2_GetVertices,
+    d3drm_face2_GetTextureCoordinates,
+    d3drm_face2_GetTextureTopology,
+    d3drm_face2_GetNormal,
+    d3drm_face2_GetTexture,
+    d3drm_face2_GetMaterial,
+    d3drm_face2_GetVertexCount,
+    d3drm_face2_GetVertexIndex,
+    d3drm_face2_GetTextureCoordinateIndex,
+    d3drm_face2_GetColor,
+};
+
+HRESULT Direct3DRMFace_create(REFIID riid, IUnknown **out)
+{
+    struct d3drm_face *object;
+
+    TRACE("riid %s, out %p.\n", debugstr_guid(riid), out);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMFace_iface.lpVtbl = &d3drm_face1_vtbl;
+    object->IDirect3DRMFace2_iface.lpVtbl = &d3drm_face2_vtbl;
+    object->ref = 1;
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMFace2))
+        *out = (IUnknown*)&object->IDirect3DRMFace2_iface;
+    else
+        *out = (IUnknown*)&object->IDirect3DRMFace_iface;
+
+    return S_OK;
+}
diff --git a/reactos/dll/directx/wine/d3drm/frame.c b/reactos/dll/directx/wine/d3drm/frame.c
new file mode 100644 (file)
index 0000000..1e0f056
--- /dev/null
@@ -0,0 +1,2297 @@
+/*
+ * Implementation of IDirect3DRMFrame Interface
+ *
+ * Copyright 2011, 2012 André Hentschel
+ * Copyright 2012 Christian Costa
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+#include <assert.h>
+
+static D3DRMMATRIX4D identity = {
+    { 1.0f, 0.0f, 0.0f, 0.0f },
+    { 0.0f, 1.0f, 0.0f, 0.0f },
+    { 0.0f, 0.0f, 1.0f, 0.0f },
+    { 0.0f, 0.0f, 0.0f, 1.0f }
+};
+
+struct d3drm_frame
+{
+    IDirect3DRMFrame2 IDirect3DRMFrame2_iface;
+    IDirect3DRMFrame3 IDirect3DRMFrame3_iface;
+    LONG ref;
+    struct d3drm_frame *parent;
+    ULONG nb_children;
+    ULONG children_capacity;
+    IDirect3DRMFrame3** children;
+    ULONG nb_visuals;
+    ULONG visuals_capacity;
+    IDirect3DRMVisual** visuals;
+    ULONG nb_lights;
+    ULONG lights_capacity;
+    IDirect3DRMLight** lights;
+    D3DRMMATRIX4D transform;
+    D3DCOLOR scenebackground;
+};
+
+struct d3drm_frame_array
+{
+    IDirect3DRMFrameArray IDirect3DRMFrameArray_iface;
+    LONG ref;
+    ULONG size;
+    IDirect3DRMFrame **frames;
+};
+
+struct d3drm_visual_array
+{
+    IDirect3DRMVisualArray IDirect3DRMVisualArray_iface;
+    LONG ref;
+    ULONG size;
+    IDirect3DRMVisual **visuals;
+};
+
+struct d3drm_light_array
+{
+    IDirect3DRMLightArray IDirect3DRMLightArray_iface;
+    LONG ref;
+    ULONG size;
+    IDirect3DRMLight **lights;
+};
+
+static inline struct d3drm_frame *impl_from_IDirect3DRMFrame2(IDirect3DRMFrame2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_frame, IDirect3DRMFrame2_iface);
+}
+
+static inline struct d3drm_frame *impl_from_IDirect3DRMFrame3(IDirect3DRMFrame3 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_frame, IDirect3DRMFrame3_iface);
+}
+
+static inline struct d3drm_frame *unsafe_impl_from_IDirect3DRMFrame3(IDirect3DRMFrame3 *iface);
+
+static inline struct d3drm_frame_array *impl_from_IDirect3DRMFrameArray(IDirect3DRMFrameArray *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_frame_array, IDirect3DRMFrameArray_iface);
+}
+
+static inline struct d3drm_visual_array *impl_from_IDirect3DRMVisualArray(IDirect3DRMVisualArray *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_visual_array, IDirect3DRMVisualArray_iface);
+}
+
+static inline struct d3drm_light_array *impl_from_IDirect3DRMLightArray(IDirect3DRMLightArray *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_light_array, IDirect3DRMLightArray_iface);
+}
+
+static HRESULT WINAPI d3drm_frame_array_QueryInterface(IDirect3DRMFrameArray *iface, REFIID riid, void **out)
+{
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMFrameArray)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        IDirect3DRMFrameArray_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI d3drm_frame_array_AddRef(IDirect3DRMFrameArray *iface)
+{
+    struct d3drm_frame_array *array = impl_from_IDirect3DRMFrameArray(iface);
+    ULONG refcount = InterlockedIncrement(&array->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_frame_array_Release(IDirect3DRMFrameArray *iface)
+{
+    struct d3drm_frame_array *array = impl_from_IDirect3DRMFrameArray(iface);
+    ULONG refcount = InterlockedDecrement(&array->ref);
+    ULONG i;
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        for (i = 0; i < array->size; ++i)
+        {
+            IDirect3DRMFrame_Release(array->frames[i]);
+        }
+        HeapFree(GetProcessHeap(), 0, array->frames);
+        HeapFree(GetProcessHeap(), 0, array);
+    }
+
+    return refcount;
+}
+
+static DWORD WINAPI d3drm_frame_array_GetSize(IDirect3DRMFrameArray *iface)
+{
+    struct d3drm_frame_array *array = impl_from_IDirect3DRMFrameArray(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return array->size;
+}
+
+static HRESULT WINAPI d3drm_frame_array_GetElement(IDirect3DRMFrameArray *iface,
+        DWORD index, IDirect3DRMFrame **frame)
+{
+    struct d3drm_frame_array *array = impl_from_IDirect3DRMFrameArray(iface);
+
+    TRACE("iface %p, index %u, frame %p.\n", iface, index, frame);
+
+    if (!frame)
+        return D3DRMERR_BADVALUE;
+
+    if (index >= array->size)
+    {
+        *frame = NULL;
+        return D3DRMERR_BADVALUE;
+    }
+
+    IDirect3DRMFrame_AddRef(array->frames[index]);
+    *frame = array->frames[index];
+
+    return D3DRM_OK;
+}
+
+static const struct IDirect3DRMFrameArrayVtbl d3drm_frame_array_vtbl =
+{
+    d3drm_frame_array_QueryInterface,
+    d3drm_frame_array_AddRef,
+    d3drm_frame_array_Release,
+    d3drm_frame_array_GetSize,
+    d3drm_frame_array_GetElement,
+};
+
+static struct d3drm_frame_array *d3drm_frame_array_create(unsigned int frame_count, IDirect3DRMFrame3 **frames)
+{
+    struct d3drm_frame_array *array;
+    unsigned int i;
+
+    if (!(array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*array))))
+        return NULL;
+
+    array->IDirect3DRMFrameArray_iface.lpVtbl = &d3drm_frame_array_vtbl;
+    array->ref = 1;
+    array->size = frame_count;
+
+    if (frame_count)
+    {
+        if (!(array->frames = HeapAlloc(GetProcessHeap(), 0, frame_count * sizeof(*array->frames))))
+        {
+            HeapFree(GetProcessHeap(), 0, array);
+            return NULL;
+        }
+
+        for (i = 0; i < frame_count; ++i)
+        {
+            IDirect3DRMFrame3_QueryInterface(frames[i], &IID_IDirect3DRMFrame, (void **)&array->frames[i]);
+        }
+    }
+
+    return array;
+}
+
+static HRESULT WINAPI d3drm_visual_array_QueryInterface(IDirect3DRMVisualArray *iface, REFIID riid, void **out)
+{
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMVisualArray)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        IDirect3DRMVisualArray_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI d3drm_visual_array_AddRef(IDirect3DRMVisualArray *iface)
+{
+    struct d3drm_visual_array *array = impl_from_IDirect3DRMVisualArray(iface);
+    ULONG refcount = InterlockedIncrement(&array->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_visual_array_Release(IDirect3DRMVisualArray *iface)
+{
+    struct d3drm_visual_array *array = impl_from_IDirect3DRMVisualArray(iface);
+    ULONG refcount = InterlockedDecrement(&array->ref);
+    ULONG i;
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        for (i = 0; i < array->size; ++i)
+        {
+            IDirect3DRMVisual_Release(array->visuals[i]);
+        }
+        HeapFree(GetProcessHeap(), 0, array->visuals);
+        HeapFree(GetProcessHeap(), 0, array);
+    }
+
+    return refcount;
+}
+
+static DWORD WINAPI d3drm_visual_array_GetSize(IDirect3DRMVisualArray *iface)
+{
+    struct d3drm_visual_array *array = impl_from_IDirect3DRMVisualArray(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return array->size;
+}
+
+static HRESULT WINAPI d3drm_visual_array_GetElement(IDirect3DRMVisualArray *iface,
+        DWORD index, IDirect3DRMVisual **visual)
+{
+    struct d3drm_visual_array *array = impl_from_IDirect3DRMVisualArray(iface);
+
+    TRACE("iface %p, index %u, visual %p.\n", iface, index, visual);
+
+    if (!visual)
+        return D3DRMERR_BADVALUE;
+
+    if (index >= array->size)
+    {
+        *visual = NULL;
+        return D3DRMERR_BADVALUE;
+    }
+
+    IDirect3DRMVisual_AddRef(array->visuals[index]);
+    *visual = array->visuals[index];
+
+    return D3DRM_OK;
+}
+
+static const struct IDirect3DRMVisualArrayVtbl d3drm_visual_array_vtbl =
+{
+    d3drm_visual_array_QueryInterface,
+    d3drm_visual_array_AddRef,
+    d3drm_visual_array_Release,
+    d3drm_visual_array_GetSize,
+    d3drm_visual_array_GetElement,
+};
+
+static struct d3drm_visual_array *d3drm_visual_array_create(unsigned int visual_count, IDirect3DRMVisual **visuals)
+{
+    struct d3drm_visual_array *array;
+    unsigned int i;
+
+    if (!(array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*array))))
+        return NULL;
+
+    array->IDirect3DRMVisualArray_iface.lpVtbl = &d3drm_visual_array_vtbl;
+    array->ref = 1;
+    array->size = visual_count;
+
+    if (visual_count)
+    {
+        if (!(array->visuals = HeapAlloc(GetProcessHeap(), 0, visual_count * sizeof(*array->visuals))))
+        {
+            HeapFree(GetProcessHeap(), 0, array);
+            return NULL;
+        }
+
+        for (i = 0; i < visual_count; ++i)
+        {
+            array->visuals[i] = visuals[i];
+            IDirect3DRMVisual_AddRef(array->visuals[i]);
+        }
+    }
+
+    return array;
+}
+
+static HRESULT WINAPI d3drm_light_array_QueryInterface(IDirect3DRMLightArray *iface, REFIID riid, void **out)
+{
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMLightArray)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        IDirect3DRMLightArray_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI d3drm_light_array_AddRef(IDirect3DRMLightArray *iface)
+{
+    struct d3drm_light_array *array = impl_from_IDirect3DRMLightArray(iface);
+    ULONG refcount = InterlockedIncrement(&array->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_light_array_Release(IDirect3DRMLightArray *iface)
+{
+    struct d3drm_light_array *array = impl_from_IDirect3DRMLightArray(iface);
+    ULONG refcount = InterlockedDecrement(&array->ref);
+    ULONG i;
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        for (i = 0; i < array->size; ++i)
+        {
+            IDirect3DRMLight_Release(array->lights[i]);
+        }
+        HeapFree(GetProcessHeap(), 0, array->lights);
+        HeapFree(GetProcessHeap(), 0, array);
+    }
+
+    return refcount;
+}
+
+static DWORD WINAPI d3drm_light_array_GetSize(IDirect3DRMLightArray *iface)
+{
+    struct d3drm_light_array *array = impl_from_IDirect3DRMLightArray(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return array->size;
+}
+
+static HRESULT WINAPI d3drm_light_array_GetElement(IDirect3DRMLightArray *iface,
+        DWORD index, IDirect3DRMLight **light)
+{
+    struct d3drm_light_array *array = impl_from_IDirect3DRMLightArray(iface);
+
+    TRACE("iface %p, index %u, light %p.\n", iface, index, light);
+
+    if (!light)
+        return D3DRMERR_BADVALUE;
+
+    if (index >= array->size)
+    {
+        *light = NULL;
+        return D3DRMERR_BADVALUE;
+    }
+
+    IDirect3DRMLight_AddRef(array->lights[index]);
+    *light = array->lights[index];
+
+    return D3DRM_OK;
+}
+
+static const struct IDirect3DRMLightArrayVtbl d3drm_light_array_vtbl =
+{
+    d3drm_light_array_QueryInterface,
+    d3drm_light_array_AddRef,
+    d3drm_light_array_Release,
+    d3drm_light_array_GetSize,
+    d3drm_light_array_GetElement,
+};
+
+static struct d3drm_light_array *d3drm_light_array_create(unsigned int light_count, IDirect3DRMLight **lights)
+{
+    struct d3drm_light_array *array;
+    unsigned int i;
+
+    if (!(array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*array))))
+        return NULL;
+
+    array->IDirect3DRMLightArray_iface.lpVtbl = &d3drm_light_array_vtbl;
+    array->ref = 1;
+    array->size = light_count;
+
+    if (light_count)
+    {
+        if (!(array->lights = HeapAlloc(GetProcessHeap(), 0, light_count * sizeof(*array->lights))))
+        {
+            HeapFree(GetProcessHeap(), 0, array);
+            return NULL;
+        }
+
+        for (i = 0; i < light_count; ++i)
+        {
+            array->lights[i] = lights[i];
+            IDirect3DRMLight_AddRef(array->lights[i]);
+        }
+    }
+
+    return array;
+}
+
+static HRESULT WINAPI d3drm_frame2_QueryInterface(IDirect3DRMFrame2 *iface, REFIID riid, void **out)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMFrame2)
+            || IsEqualGUID(riid, &IID_IDirect3DRMFrame)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *out = &frame->IDirect3DRMFrame2_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRMFrame3))
+    {
+        *out = &frame->IDirect3DRMFrame3_iface;
+    }
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI d3drm_frame2_AddRef(IDirect3DRMFrame2 *iface)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+    ULONG refcount = InterlockedIncrement(&frame->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_frame2_Release(IDirect3DRMFrame2 *iface)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+    ULONG refcount = InterlockedDecrement(&frame->ref);
+    ULONG i;
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        for (i = 0; i < frame->nb_children; ++i)
+        {
+            IDirect3DRMFrame3_Release(frame->children[i]);
+        }
+        HeapFree(GetProcessHeap(), 0, frame->children);
+        for (i = 0; i < frame->nb_visuals; ++i)
+        {
+            IDirect3DRMVisual_Release(frame->visuals[i]);
+        }
+        HeapFree(GetProcessHeap(), 0, frame->visuals);
+        for (i = 0; i < frame->nb_lights; ++i)
+        {
+            IDirect3DRMLight_Release(frame->lights[i]);
+        }
+        HeapFree(GetProcessHeap(), 0, frame->lights);
+        HeapFree(GetProcessHeap(), 0, frame);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_frame2_Clone(IDirect3DRMFrame2 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_AddDestroyCallback(IDirect3DRMFrame2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_DeleteDestroyCallback(IDirect3DRMFrame2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetAppData(IDirect3DRMFrame2 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_frame2_GetAppData(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetName(IDirect3DRMFrame2 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetName(IDirect3DRMFrame2 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetClassName(IDirect3DRMFrame2 *iface, DWORD *size, char *name)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    return IDirect3DRMFrame3_GetClassName(&frame->IDirect3DRMFrame3_iface, size, name);
+}
+
+static HRESULT WINAPI d3drm_frame2_AddChild(IDirect3DRMFrame2 *iface, IDirect3DRMFrame *child)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+    IDirect3DRMFrame3 *child3;
+    HRESULT hr;
+
+    TRACE("iface %p, child %p.\n", iface, child);
+
+    if (!child)
+        return D3DRMERR_BADOBJECT;
+    hr = IDirect3DRMFrame_QueryInterface(child, &IID_IDirect3DRMFrame3, (void **)&child3);
+    if (hr != S_OK)
+        return D3DRMERR_BADOBJECT;
+    IDirect3DRMFrame_Release(child);
+
+    return IDirect3DRMFrame3_AddChild(&frame->IDirect3DRMFrame3_iface, child3);
+}
+
+static HRESULT WINAPI d3drm_frame2_AddLight(IDirect3DRMFrame2 *iface, IDirect3DRMLight *light)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, light %p.\n", iface, light);
+
+    return IDirect3DRMFrame3_AddLight(&frame->IDirect3DRMFrame3_iface, light);
+}
+
+static HRESULT WINAPI d3drm_frame2_AddMoveCallback(IDirect3DRMFrame2 *iface,
+        D3DRMFRAMEMOVECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_AddTransform(IDirect3DRMFrame2 *iface, D3DRMCOMBINETYPE type, D3DRMMATRIX4D matrix)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, type %#x, matrix %p.\n", iface, type, matrix);
+
+    return IDirect3DRMFrame3_AddTransform(&frame->IDirect3DRMFrame3_iface, type, matrix);
+}
+
+static HRESULT WINAPI d3drm_frame2_AddTranslation(IDirect3DRMFrame2 *iface,
+        D3DRMCOMBINETYPE type, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, type %#x, x %.8e, y %.8e, z %.8e stub!\n", iface, type, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_AddScale(IDirect3DRMFrame2 *iface,
+        D3DRMCOMBINETYPE type, D3DVALUE sx, D3DVALUE sy, D3DVALUE sz)
+{
+    FIXME("iface %p, type %#x, sx %.8e, sy %.8e, sz %.8e stub!\n", iface, type, sx, sy, sz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_AddRotation(IDirect3DRMFrame2 *iface,
+        D3DRMCOMBINETYPE type, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta)
+{
+    FIXME("iface %p, type %#x, x %.8e, y %.8e, z %.8e, theta %.8e stub!\n", iface, type, x, y, z, theta);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_AddVisual(IDirect3DRMFrame2 *iface, IDirect3DRMVisual *visual)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, visual %p.\n", iface, visual);
+
+    return IDirect3DRMFrame3_AddVisual(&frame->IDirect3DRMFrame3_iface, (IUnknown *)visual);
+}
+
+static HRESULT WINAPI d3drm_frame2_GetChildren(IDirect3DRMFrame2 *iface, IDirect3DRMFrameArray **children)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, children %p.\n", iface, children);
+
+    return IDirect3DRMFrame3_GetChildren(&frame->IDirect3DRMFrame3_iface, children);
+}
+
+static D3DCOLOR WINAPI d3drm_frame2_GetColor(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetLights(IDirect3DRMFrame2 *iface, IDirect3DRMLightArray **lights)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, lights %p.\n", iface, lights);
+
+    return IDirect3DRMFrame3_GetLights(&frame->IDirect3DRMFrame3_iface, lights);
+}
+
+static D3DRMMATERIALMODE WINAPI d3drm_frame2_GetMaterialMode(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRMMATERIAL_FROMPARENT;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetParent(IDirect3DRMFrame2 *iface, IDirect3DRMFrame **parent)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, parent %p.\n", iface, parent);
+
+    if (!parent)
+        return D3DRMERR_BADVALUE;
+
+    if (frame->parent)
+    {
+        *parent = (IDirect3DRMFrame *)&frame->parent->IDirect3DRMFrame2_iface;
+        IDirect3DRMFrame_AddRef(*parent);
+    }
+    else
+    {
+        *parent = NULL;
+    }
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetPosition(IDirect3DRMFrame2 *iface,
+        IDirect3DRMFrame *reference, D3DVECTOR *position)
+{
+    FIXME("iface %p, reference %p, position %p stub!\n", iface, reference, position);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetRotation(IDirect3DRMFrame2 *iface,
+        IDirect3DRMFrame *reference, D3DVECTOR *axis, D3DVALUE *theta)
+{
+    FIXME("iface %p, reference %p, axis %p, theta %p stub!\n", iface, reference, axis, theta);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetScene(IDirect3DRMFrame2 *iface, IDirect3DRMFrame **scene)
+{
+    FIXME("iface %p, scene %p stub!\n", iface, scene);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMSORTMODE WINAPI d3drm_frame2_GetSortMode(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRMSORT_FROMPARENT;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetTexture(IDirect3DRMFrame2 *iface, IDirect3DRMTexture **texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetTransform(IDirect3DRMFrame2 *iface, D3DRMMATRIX4D matrix)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, matrix %p.\n", iface, matrix);
+
+    memcpy(matrix, frame->transform, sizeof(D3DRMMATRIX4D));
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetVelocity(IDirect3DRMFrame2 *iface,
+        IDirect3DRMFrame *reference, D3DVECTOR *velocity, BOOL with_rotation)
+{
+    FIXME("iface %p, reference %p, velocity %p, with_rotation %#x stub!\n",
+            iface, reference, velocity, with_rotation);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetOrientation(IDirect3DRMFrame2 *iface,
+        IDirect3DRMFrame *reference, D3DVECTOR *dir, D3DVECTOR *up)
+{
+    FIXME("iface %p, reference %p, dir %p, up %p stub!\n", iface, reference, dir, up);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetVisuals(IDirect3DRMFrame2 *iface, IDirect3DRMVisualArray **visuals)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+    struct d3drm_visual_array *array;
+
+    TRACE("iface %p, visuals %p.\n", iface, visuals);
+
+    if (!visuals)
+        return D3DRMERR_BADVALUE;
+
+    if (!(array = d3drm_visual_array_create(frame->nb_visuals, frame->visuals)))
+        return E_OUTOFMEMORY;
+
+    *visuals = &array->IDirect3DRMVisualArray_iface;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetTextureTopology(IDirect3DRMFrame2 *iface, BOOL *wrap_u, BOOL *wrap_v)
+{
+    FIXME("iface %p, wrap_u %p, wrap_v %p stub!\n", iface, wrap_u, wrap_v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_InverseTransform(IDirect3DRMFrame2 *iface, D3DVECTOR *d, D3DVECTOR *s)
+{
+    FIXME("iface %p, d %p, s %p stub!\n", iface, d, s);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_Load(IDirect3DRMFrame2 *iface, void *filename,
+        void *name, D3DRMLOADOPTIONS flags, D3DRMLOADTEXTURECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, filename %p, name %p, flags %#x, cb %p, ctx %p stub!\n",
+            iface, filename, name, flags, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_LookAt(IDirect3DRMFrame2 *iface, IDirect3DRMFrame *target,
+        IDirect3DRMFrame *reference, D3DRMFRAMECONSTRAINT constraint)
+{
+    FIXME("iface %p, target %p, reference %p, constraint %#x stub!\n", iface, target, reference, constraint);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_Move(IDirect3DRMFrame2 *iface, D3DVALUE delta)
+{
+    FIXME("iface %p, delta %.8e stub!\n", iface, delta);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_DeleteChild(IDirect3DRMFrame2 *iface, IDirect3DRMFrame *child)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+    IDirect3DRMFrame3 *child3;
+    HRESULT hr;
+
+    TRACE("iface %p, child %p.\n", iface, child);
+
+    if (!child)
+        return D3DRMERR_BADOBJECT;
+    if (FAILED(hr = IDirect3DRMFrame_QueryInterface(child, &IID_IDirect3DRMFrame3, (void **)&child3)))
+        return D3DRMERR_BADOBJECT;
+    IDirect3DRMFrame_Release(child);
+
+    return IDirect3DRMFrame3_DeleteChild(&frame->IDirect3DRMFrame3_iface, child3);
+}
+
+static HRESULT WINAPI d3drm_frame2_DeleteLight(IDirect3DRMFrame2 *iface, IDirect3DRMLight *light)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, light %p.\n", iface, light);
+
+    return IDirect3DRMFrame3_DeleteLight(&frame->IDirect3DRMFrame3_iface, light);
+}
+
+static HRESULT WINAPI d3drm_frame2_DeleteMoveCallback(IDirect3DRMFrame2 *iface,
+        D3DRMFRAMEMOVECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_DeleteVisual(IDirect3DRMFrame2 *iface, IDirect3DRMVisual *visual)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, visual %p.\n", iface, visual);
+
+    return IDirect3DRMFrame3_DeleteVisual(&frame->IDirect3DRMFrame3_iface, (IUnknown *)visual);
+}
+
+static D3DCOLOR WINAPI d3drm_frame2_GetSceneBackground(IDirect3DRMFrame2 *iface)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMFrame3_GetSceneBackground(&frame->IDirect3DRMFrame3_iface);
+}
+
+static HRESULT WINAPI d3drm_frame2_GetSceneBackgroundDepth(IDirect3DRMFrame2 *iface,
+        IDirectDrawSurface **surface)
+{
+    FIXME("iface %p, surface %p stub!\n", iface, surface);
+
+    return E_NOTIMPL;
+}
+
+static D3DCOLOR WINAPI d3drm_frame2_GetSceneFogColor(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static BOOL WINAPI d3drm_frame2_GetSceneFogEnable(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return FALSE;
+}
+
+static D3DRMFOGMODE WINAPI d3drm_frame2_GetSceneFogMode(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRMFOG_LINEAR;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetSceneFogParams(IDirect3DRMFrame2 *iface,
+        D3DVALUE *start, D3DVALUE *end, D3DVALUE *density)
+{
+    FIXME("iface %p, start %p, end %p, density %p stub!\n", iface, start, end, density);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSceneBackground(IDirect3DRMFrame2 *iface, D3DCOLOR color)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, color 0x%08x.\n", iface, color);
+
+    return IDirect3DRMFrame3_SetSceneBackground(&frame->IDirect3DRMFrame3_iface, color);
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSceneBackgroundRGB(IDirect3DRMFrame2 *iface,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame2(iface);
+
+    TRACE("iface %p, red %.8e, green %.8e, blue %.8e.\n", iface, red, green, blue);
+
+    return IDirect3DRMFrame3_SetSceneBackgroundRGB(&frame->IDirect3DRMFrame3_iface, red, green, blue);
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSceneBackgroundDepth(IDirect3DRMFrame2 *iface, IDirectDrawSurface *surface)
+{
+    FIXME("iface %p, surface %p stub!\n", iface, surface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSceneBackgroundImage(IDirect3DRMFrame2 *iface, IDirect3DRMTexture *texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSceneFogEnable(IDirect3DRMFrame2 *iface, BOOL enable)
+{
+    FIXME("iface %p, enable %#x stub!\n", iface, enable);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSceneFogColor(IDirect3DRMFrame2 *iface, D3DCOLOR color)
+{
+    FIXME("iface %p, color 0x%08x stub!\n", iface, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSceneFogMode(IDirect3DRMFrame2 *iface, D3DRMFOGMODE mode)
+{
+    FIXME("iface %p, mode %#x stub!\n", iface, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSceneFogParams(IDirect3DRMFrame2 *iface,
+        D3DVALUE start, D3DVALUE end, D3DVALUE density)
+{
+    FIXME("iface %p, start %.8e, end %.8e, density %.8e stub!\n", iface, start, end, density);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetColor(IDirect3DRMFrame2 *iface, D3DCOLOR color)
+{
+    FIXME("iface %p, color 0x%08x stub!\n", iface, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetColorRGB(IDirect3DRMFrame2 *iface,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    FIXME("iface %p, red %.8e, green %.8e, blue %.8e stub!\n", iface, red, green, blue);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMZBUFFERMODE WINAPI d3drm_frame2_GetZbufferMode(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRMZBUFFER_FROMPARENT;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetMaterialMode(IDirect3DRMFrame2 *iface, D3DRMMATERIALMODE mode)
+{
+    FIXME("iface %p, mode %#x stub!\n", iface, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetOrientation(IDirect3DRMFrame2 *iface, IDirect3DRMFrame *reference,
+        D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, D3DVALUE ux, D3DVALUE uy, D3DVALUE uz)
+{
+    FIXME("iface %p, reference %p, dx %.8e, dy %.8e, dz %.8e, ux %.8e, uy %.8e, uz %.8e stub!\n",
+            iface, reference, dx, dy, dz, ux, uy, uz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetPosition(IDirect3DRMFrame2 *iface,
+        IDirect3DRMFrame *reference, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, reference %p, x %.8e, y %.8e, z %.8e stub!\n", iface, reference, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetRotation(IDirect3DRMFrame2 *iface,
+        IDirect3DRMFrame *reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta)
+{
+    FIXME("iface %p, reference %p, x %.8e, y %.8e, z %.8e, theta %.8e stub!\n",
+            iface, reference, x, y, z, theta);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetSortMode(IDirect3DRMFrame2 *iface, D3DRMSORTMODE mode)
+{
+    FIXME("iface %p, mode %#x stub!\n", iface, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetTexture(IDirect3DRMFrame2 *iface, IDirect3DRMTexture *texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetTextureTopology(IDirect3DRMFrame2 *iface, BOOL wrap_u, BOOL wrap_v)
+{
+    FIXME("iface %p, wrap_u %#x, wrap_v %#x stub!\n", iface, wrap_u, wrap_v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetVelocity(IDirect3DRMFrame2 *iface,
+        IDirect3DRMFrame *reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, BOOL with_rotation)
+{
+    FIXME("iface %p, reference %p, x %.8e, y %.8e, z %.8e, with_rotation %#x stub!\n",
+            iface, reference, x, y, z, with_rotation);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_SetZbufferMode(IDirect3DRMFrame2 *iface, D3DRMZBUFFERMODE mode)
+{
+    FIXME("iface %p, mode %#x stub!\n", iface, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_Transform(IDirect3DRMFrame2 *iface, D3DVECTOR *d, D3DVECTOR *s)
+{
+    FIXME("iface %p, d %p, s %p stub!\n", iface, d, s);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_AddMoveCallback2(IDirect3DRMFrame2 *iface,
+        D3DRMFRAMEMOVECALLBACK cb, void *ctx, DWORD flags)
+{
+    FIXME("iface %p, cb %p, ctx %p, flags %#x stub!\n", iface, cb, ctx, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetBox(IDirect3DRMFrame2 *iface, D3DRMBOX *box)
+{
+    FIXME("iface %p, box %p stub!\n", iface, box);
+
+    return E_NOTIMPL;
+}
+
+static BOOL WINAPI d3drm_frame2_GetBoxEnable(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetAxes(IDirect3DRMFrame2 *iface, D3DVECTOR *dir, D3DVECTOR *up)
+{
+    FIXME("iface %p, dir %p, up %p stub!\n", iface, dir, up);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetMaterial(IDirect3DRMFrame2 *iface, IDirect3DRMMaterial **material)
+{
+    FIXME("iface %p, material %p stub!\n", iface, material);
+
+    return E_NOTIMPL;
+}
+
+static BOOL WINAPI d3drm_frame2_GetInheritAxes(IDirect3DRMFrame2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame2_GetHierarchyBox(IDirect3DRMFrame2 *iface, D3DRMBOX *box)
+{
+    FIXME("iface %p, box %p stub!\n", iface, box);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMFrame2Vtbl d3drm_frame2_vtbl =
+{
+    d3drm_frame2_QueryInterface,
+    d3drm_frame2_AddRef,
+    d3drm_frame2_Release,
+    d3drm_frame2_Clone,
+    d3drm_frame2_AddDestroyCallback,
+    d3drm_frame2_DeleteDestroyCallback,
+    d3drm_frame2_SetAppData,
+    d3drm_frame2_GetAppData,
+    d3drm_frame2_SetName,
+    d3drm_frame2_GetName,
+    d3drm_frame2_GetClassName,
+    d3drm_frame2_AddChild,
+    d3drm_frame2_AddLight,
+    d3drm_frame2_AddMoveCallback,
+    d3drm_frame2_AddTransform,
+    d3drm_frame2_AddTranslation,
+    d3drm_frame2_AddScale,
+    d3drm_frame2_AddRotation,
+    d3drm_frame2_AddVisual,
+    d3drm_frame2_GetChildren,
+    d3drm_frame2_GetColor,
+    d3drm_frame2_GetLights,
+    d3drm_frame2_GetMaterialMode,
+    d3drm_frame2_GetParent,
+    d3drm_frame2_GetPosition,
+    d3drm_frame2_GetRotation,
+    d3drm_frame2_GetScene,
+    d3drm_frame2_GetSortMode,
+    d3drm_frame2_GetTexture,
+    d3drm_frame2_GetTransform,
+    d3drm_frame2_GetVelocity,
+    d3drm_frame2_GetOrientation,
+    d3drm_frame2_GetVisuals,
+    d3drm_frame2_GetTextureTopology,
+    d3drm_frame2_InverseTransform,
+    d3drm_frame2_Load,
+    d3drm_frame2_LookAt,
+    d3drm_frame2_Move,
+    d3drm_frame2_DeleteChild,
+    d3drm_frame2_DeleteLight,
+    d3drm_frame2_DeleteMoveCallback,
+    d3drm_frame2_DeleteVisual,
+    d3drm_frame2_GetSceneBackground,
+    d3drm_frame2_GetSceneBackgroundDepth,
+    d3drm_frame2_GetSceneFogColor,
+    d3drm_frame2_GetSceneFogEnable,
+    d3drm_frame2_GetSceneFogMode,
+    d3drm_frame2_GetSceneFogParams,
+    d3drm_frame2_SetSceneBackground,
+    d3drm_frame2_SetSceneBackgroundRGB,
+    d3drm_frame2_SetSceneBackgroundDepth,
+    d3drm_frame2_SetSceneBackgroundImage,
+    d3drm_frame2_SetSceneFogEnable,
+    d3drm_frame2_SetSceneFogColor,
+    d3drm_frame2_SetSceneFogMode,
+    d3drm_frame2_SetSceneFogParams,
+    d3drm_frame2_SetColor,
+    d3drm_frame2_SetColorRGB,
+    d3drm_frame2_GetZbufferMode,
+    d3drm_frame2_SetMaterialMode,
+    d3drm_frame2_SetOrientation,
+    d3drm_frame2_SetPosition,
+    d3drm_frame2_SetRotation,
+    d3drm_frame2_SetSortMode,
+    d3drm_frame2_SetTexture,
+    d3drm_frame2_SetTextureTopology,
+    d3drm_frame2_SetVelocity,
+    d3drm_frame2_SetZbufferMode,
+    d3drm_frame2_Transform,
+    d3drm_frame2_AddMoveCallback2,
+    d3drm_frame2_GetBox,
+    d3drm_frame2_GetBoxEnable,
+    d3drm_frame2_GetAxes,
+    d3drm_frame2_GetMaterial,
+    d3drm_frame2_GetInheritAxes,
+    d3drm_frame2_GetHierarchyBox,
+};
+
+static HRESULT WINAPI d3drm_frame3_QueryInterface(IDirect3DRMFrame3 *iface, REFIID riid, void **out)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    return d3drm_frame2_QueryInterface(&frame->IDirect3DRMFrame2_iface, riid, out);
+}
+
+static ULONG WINAPI d3drm_frame3_AddRef(IDirect3DRMFrame3 *iface)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return d3drm_frame2_AddRef(&frame->IDirect3DRMFrame2_iface);
+}
+
+static ULONG WINAPI d3drm_frame3_Release(IDirect3DRMFrame3 *iface)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return d3drm_frame2_Release(&frame->IDirect3DRMFrame2_iface);
+}
+
+static HRESULT WINAPI d3drm_frame3_Clone(IDirect3DRMFrame3 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddDestroyCallback(IDirect3DRMFrame3 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_DeleteDestroyCallback(IDirect3DRMFrame3 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetAppData(IDirect3DRMFrame3 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_frame3_GetAppData(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetName(IDirect3DRMFrame3 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetName(IDirect3DRMFrame3 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetClassName(IDirect3DRMFrame3 *iface, DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Frame") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Frame");
+    *size = sizeof("Frame");
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddChild(IDirect3DRMFrame3 *iface, IDirect3DRMFrame3 *child)
+{
+    struct d3drm_frame *This = impl_from_IDirect3DRMFrame3(iface);
+    struct d3drm_frame *child_obj = unsafe_impl_from_IDirect3DRMFrame3(child);
+
+    TRACE("iface %p, child %p.\n", iface, child);
+
+    if (!child_obj)
+        return D3DRMERR_BADOBJECT;
+
+    if (child_obj->parent)
+    {
+        IDirect3DRMFrame3* parent = &child_obj->parent->IDirect3DRMFrame3_iface;
+
+        if (parent == iface)
+        {
+            /* Passed frame is already a child so return success */
+            return D3DRM_OK;
+        }
+        else
+        {
+            /* Remove parent and continue */
+            IDirect3DRMFrame3_DeleteChild(parent, child);
+        }
+    }
+
+    if ((This->nb_children + 1) > This->children_capacity)
+    {
+        ULONG new_capacity;
+        IDirect3DRMFrame3** children;
+
+        if (!This->children_capacity)
+        {
+            new_capacity = 16;
+            children = HeapAlloc(GetProcessHeap(), 0, new_capacity * sizeof(IDirect3DRMFrame3*));
+        }
+        else
+        {
+            new_capacity = This->children_capacity * 2;
+            children = HeapReAlloc(GetProcessHeap(), 0, This->children, new_capacity * sizeof(IDirect3DRMFrame3*));
+        }
+
+        if (!children)
+            return E_OUTOFMEMORY;
+
+        This->children_capacity = new_capacity;
+        This->children = children;
+    }
+
+    This->children[This->nb_children++] = child;
+    IDirect3DRMFrame3_AddRef(child);
+    child_obj->parent = This;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddLight(IDirect3DRMFrame3 *iface, IDirect3DRMLight *light)
+{
+    struct d3drm_frame *This = impl_from_IDirect3DRMFrame3(iface);
+    ULONG i;
+    IDirect3DRMLight** lights;
+
+    TRACE("iface %p, light %p.\n", iface, light);
+
+    if (!light)
+        return D3DRMERR_BADOBJECT;
+
+    /* Check if already existing and return gracefully without increasing ref count */
+    for (i = 0; i < This->nb_lights; i++)
+        if (This->lights[i] == light)
+            return D3DRM_OK;
+
+    if ((This->nb_lights + 1) > This->lights_capacity)
+    {
+        ULONG new_capacity;
+
+        if (!This->lights_capacity)
+        {
+            new_capacity = 16;
+            lights = HeapAlloc(GetProcessHeap(), 0, new_capacity * sizeof(IDirect3DRMLight*));
+        }
+        else
+        {
+            new_capacity = This->lights_capacity * 2;
+            lights = HeapReAlloc(GetProcessHeap(), 0, This->lights, new_capacity * sizeof(IDirect3DRMLight*));
+        }
+
+        if (!lights)
+            return E_OUTOFMEMORY;
+
+        This->lights_capacity = new_capacity;
+        This->lights = lights;
+    }
+
+    This->lights[This->nb_lights++] = light;
+    IDirect3DRMLight_AddRef(light);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddMoveCallback(IDirect3DRMFrame3 *iface,
+        D3DRMFRAME3MOVECALLBACK cb, void *ctx, DWORD flags)
+{
+    FIXME("iface %p, cb %p, ctx %p flags %#x stub!\n", iface, cb, ctx, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddTransform(IDirect3DRMFrame3 *iface,
+        D3DRMCOMBINETYPE type, D3DRMMATRIX4D matrix)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p, type %#x, matrix %p.\n", iface, type, matrix);
+
+    switch (type)
+    {
+        case D3DRMCOMBINE_REPLACE:
+            memcpy(frame->transform, matrix, sizeof(D3DRMMATRIX4D));
+            break;
+
+        case D3DRMCOMBINE_BEFORE:
+            FIXME("D3DRMCOMBINE_BEFORE not supported yet\n");
+            break;
+
+        case D3DRMCOMBINE_AFTER:
+            FIXME("D3DRMCOMBINE_AFTER not supported yet\n");
+            break;
+
+        default:
+            WARN("Unknown Combine Type %u\n", type);
+            return D3DRMERR_BADVALUE;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddTranslation(IDirect3DRMFrame3 *iface,
+        D3DRMCOMBINETYPE type, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, type %#x, x %.8e, y %.8e, z %.8e stub!\n", iface, type, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddScale(IDirect3DRMFrame3 *iface,
+        D3DRMCOMBINETYPE type, D3DVALUE sx, D3DVALUE sy, D3DVALUE sz)
+{
+    FIXME("iface %p, type %#x, sx %.8e, sy %.8e, sz %.8e stub!\n", iface, type, sx, sy, sz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddRotation(IDirect3DRMFrame3 *iface,
+        D3DRMCOMBINETYPE type, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta)
+{
+    FIXME("iface %p, type %#x, x %.8e, y %.8e, z %.8e, theta %.8e stub!\n",
+            iface, type, x, y, z, theta);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_AddVisual(IDirect3DRMFrame3 *iface, IUnknown *visual)
+{
+    struct d3drm_frame *This = impl_from_IDirect3DRMFrame3(iface);
+    ULONG i;
+    IDirect3DRMVisual** visuals;
+
+    TRACE("iface %p, visual %p.\n", iface, visual);
+
+    if (!visual)
+        return D3DRMERR_BADOBJECT;
+
+    /* Check if already existing and return gracefully without increasing ref count */
+    for (i = 0; i < This->nb_visuals; i++)
+        if (This->visuals[i] == (IDirect3DRMVisual *)visual)
+            return D3DRM_OK;
+
+    if ((This->nb_visuals + 1) > This->visuals_capacity)
+    {
+        ULONG new_capacity;
+
+        if (!This->visuals_capacity)
+        {
+            new_capacity = 16;
+            visuals = HeapAlloc(GetProcessHeap(), 0, new_capacity * sizeof(IDirect3DRMVisual*));
+        }
+        else
+        {
+            new_capacity = This->visuals_capacity * 2;
+            visuals = HeapReAlloc(GetProcessHeap(), 0, This->visuals, new_capacity * sizeof(IDirect3DRMVisual*));
+        }
+
+        if (!visuals)
+            return E_OUTOFMEMORY;
+
+        This->visuals_capacity = new_capacity;
+        This->visuals = visuals;
+    }
+
+    This->visuals[This->nb_visuals++] = (IDirect3DRMVisual *)visual;
+    IDirect3DRMVisual_AddRef(visual);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetChildren(IDirect3DRMFrame3 *iface, IDirect3DRMFrameArray **children)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+    struct d3drm_frame_array *array;
+
+    TRACE("iface %p, children %p.\n", iface, children);
+
+    if (!children)
+        return D3DRMERR_BADVALUE;
+
+    if (!(array = d3drm_frame_array_create(frame->nb_children, frame->children)))
+        return E_OUTOFMEMORY;
+
+    *children = &array->IDirect3DRMFrameArray_iface;
+
+    return D3DRM_OK;
+}
+
+static D3DCOLOR WINAPI d3drm_frame3_GetColor(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetLights(IDirect3DRMFrame3 *iface, IDirect3DRMLightArray **lights)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+    struct d3drm_light_array *array;
+
+    TRACE("iface %p, lights %p.\n", iface, lights);
+
+    if (!lights)
+        return D3DRMERR_BADVALUE;
+
+    if (!(array = d3drm_light_array_create(frame->nb_lights, frame->lights)))
+        return E_OUTOFMEMORY;
+
+    *lights = &array->IDirect3DRMLightArray_iface;
+
+    return D3DRM_OK;
+}
+
+static D3DRMMATERIALMODE WINAPI d3drm_frame3_GetMaterialMode(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRMMATERIAL_FROMPARENT;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetParent(IDirect3DRMFrame3 *iface, IDirect3DRMFrame3 **parent)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p, parent %p.\n", iface, parent);
+
+    if (!parent)
+        return D3DRMERR_BADVALUE;
+
+    if (frame->parent)
+    {
+        *parent = &frame->parent->IDirect3DRMFrame3_iface;
+        IDirect3DRMFrame_AddRef(*parent);
+    }
+    else
+    {
+        *parent = NULL;
+    }
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetPosition(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DVECTOR *position)
+{
+    FIXME("iface %p, reference %p, position %p stub!\n", iface, reference, position);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetRotation(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DVECTOR *axis, D3DVALUE *theta)
+{
+    FIXME("iface %p, reference %p, axis %p, theta %p stub!\n", iface, reference, axis, theta);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetScene(IDirect3DRMFrame3 *iface, IDirect3DRMFrame3 **scene)
+{
+    FIXME("iface %p, scene %p stub!\n", iface, scene);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMSORTMODE WINAPI d3drm_frame3_GetSortMode(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRMSORT_FROMPARENT;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetTexture(IDirect3DRMFrame3 *iface, IDirect3DRMTexture3 **texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetTransform(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DRMMATRIX4D matrix)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p, reference %p, matrix %p.\n", iface, reference, matrix);
+
+    if (reference)
+        FIXME("Specifying a frame as the root of the scene different from the current root frame is not supported yet\n");
+
+    memcpy(matrix, frame->transform, sizeof(D3DRMMATRIX4D));
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetVelocity(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DVECTOR *velocity, BOOL with_rotation)
+{
+    FIXME("iface %p, reference %p, velocity %p, with_rotation %#x stub!\n",
+            iface, reference, velocity, with_rotation);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetOrientation(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DVECTOR *dir, D3DVECTOR *up)
+{
+    FIXME("iface %p, reference %p, dir %p, up %p stub!\n", iface, reference, dir, up);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetVisuals(IDirect3DRMFrame3 *iface,
+        DWORD *count, IUnknown **visuals)
+{
+    FIXME("iface %p, count %p, visuals %p stub!\n", iface, count, visuals);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_InverseTransform(IDirect3DRMFrame3 *iface, D3DVECTOR *d, D3DVECTOR *s)
+{
+    FIXME("iface %p, d %p, s %p stub!\n", iface, d, s);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_Load(IDirect3DRMFrame3 *iface, void *filename,
+        void *name, D3DRMLOADOPTIONS flags, D3DRMLOADTEXTURE3CALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, filename %p, name %p, flags %#x, cb %p, ctx %p stub!\n",
+            iface, filename, name, flags, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_LookAt(IDirect3DRMFrame3 *iface, IDirect3DRMFrame3 *target,
+        IDirect3DRMFrame3 *reference, D3DRMFRAMECONSTRAINT constraint)
+{
+    FIXME("iface %p, target %p, reference %p, constraint %#x stub!\n", iface, target, reference, constraint);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_Move(IDirect3DRMFrame3 *iface, D3DVALUE delta)
+{
+    FIXME("iface %p, delta %.8e stub!\n", iface, delta);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_DeleteChild(IDirect3DRMFrame3 *iface, IDirect3DRMFrame3 *child)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+    struct d3drm_frame *child_impl = unsafe_impl_from_IDirect3DRMFrame3(child);
+    ULONG i;
+
+    TRACE("iface %p, child %p.\n", iface, child);
+
+    if (!child_impl)
+        return D3DRMERR_BADOBJECT;
+
+    /* Check if child exists */
+    for (i = 0; i < frame->nb_children; ++i)
+    {
+        if (frame->children[i] == child)
+            break;
+    }
+
+    if (i == frame->nb_children)
+        return D3DRMERR_BADVALUE;
+
+    memmove(frame->children + i, frame->children + i + 1, sizeof(*frame->children) * (frame->nb_children - 1 - i));
+    IDirect3DRMFrame3_Release(child);
+    child_impl->parent = NULL;
+    --frame->nb_children;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_DeleteLight(IDirect3DRMFrame3 *iface, IDirect3DRMLight *light)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+    ULONG i;
+
+    TRACE("iface %p, light %p.\n", iface, light);
+
+    if (!light)
+        return D3DRMERR_BADOBJECT;
+
+    /* Check if visual exists */
+    for (i = 0; i < frame->nb_lights; ++i)
+    {
+        if (frame->lights[i] == light)
+            break;
+    }
+
+    if (i == frame->nb_lights)
+        return D3DRMERR_BADVALUE;
+
+    memmove(frame->lights + i, frame->lights + i + 1, sizeof(*frame->lights) * (frame->nb_lights - 1 - i));
+    IDirect3DRMLight_Release(light);
+    --frame->nb_lights;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_DeleteMoveCallback(IDirect3DRMFrame3 *iface,
+        D3DRMFRAME3MOVECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_DeleteVisual(IDirect3DRMFrame3 *iface, IUnknown *visual)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+    ULONG i;
+
+    TRACE("iface %p, visual %p.\n", iface, visual);
+
+    if (!visual)
+        return D3DRMERR_BADOBJECT;
+
+    /* Check if visual exists */
+    for (i = 0; i < frame->nb_visuals; ++i)
+    {
+        if (frame->visuals[i] == (IDirect3DRMVisual *)visual)
+            break;
+    }
+
+    if (i == frame->nb_visuals)
+        return D3DRMERR_BADVALUE;
+
+    memmove(frame->visuals + i, frame->visuals + i + 1, sizeof(*frame->visuals) * (frame->nb_visuals - 1 - i));
+    IDirect3DRMVisual_Release(visual);
+    --frame->nb_visuals;
+
+    return D3DRM_OK;
+}
+
+static D3DCOLOR WINAPI d3drm_frame3_GetSceneBackground(IDirect3DRMFrame3 *iface)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return frame->scenebackground;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetSceneBackgroundDepth(IDirect3DRMFrame3 *iface,
+        IDirectDrawSurface **surface)
+{
+    FIXME("iface %p, surface %p stub!\n", iface, surface);
+
+    return E_NOTIMPL;
+}
+
+static D3DCOLOR WINAPI d3drm_frame3_GetSceneFogColor(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static BOOL WINAPI d3drm_frame3_GetSceneFogEnable(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return FALSE;
+}
+
+static D3DRMFOGMODE WINAPI d3drm_frame3_GetSceneFogMode(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRMFOG_LINEAR;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetSceneFogParams(IDirect3DRMFrame3 *iface,
+        D3DVALUE *start, D3DVALUE *end, D3DVALUE *density)
+{
+    FIXME("iface %p, start %p, end %p, density %p stub!\n", iface, start, end, density);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneBackground(IDirect3DRMFrame3 *iface, D3DCOLOR color)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p, color 0x%08x.\n", iface, color);
+
+    frame->scenebackground = color;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneBackgroundRGB(IDirect3DRMFrame3 *iface,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    struct d3drm_frame *frame = impl_from_IDirect3DRMFrame3(iface);
+
+    TRACE("iface %p, red %.8e, green %.8e, blue %.8e stub!\n", iface, red, green, blue);
+
+    frame->scenebackground = RGBA_MAKE((BYTE)(red * 255.0f),
+            (BYTE)(green * 255.0f), (BYTE)(blue * 255.0f), 0xff);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneBackgroundDepth(IDirect3DRMFrame3 *iface,
+        IDirectDrawSurface *surface)
+{
+    FIXME("iface %p, surface %p stub!\n", iface, surface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneBackgroundImage(IDirect3DRMFrame3 *iface,
+        IDirect3DRMTexture3 *texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneFogEnable(IDirect3DRMFrame3 *iface, BOOL enable)
+{
+    FIXME("iface %p, enable %#x stub!\n", iface, enable);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneFogColor(IDirect3DRMFrame3 *iface, D3DCOLOR color)
+{
+    FIXME("iface %p, color 0x%08x stub!\n", iface, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneFogMode(IDirect3DRMFrame3 *iface, D3DRMFOGMODE mode)
+{
+    FIXME("iface %p, mode %#x stub!\n", iface, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneFogParams(IDirect3DRMFrame3 *iface,
+        D3DVALUE start, D3DVALUE end, D3DVALUE density)
+{
+    FIXME("iface %p, start %.8e, end %.8e, density %.8e stub!\n", iface, start, end, density);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetColor(IDirect3DRMFrame3 *iface, D3DCOLOR color)
+{
+    FIXME("iface %p, color 0x%08x stub!\n", iface, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetColorRGB(IDirect3DRMFrame3 *iface,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    FIXME("iface %p, red %.8e, green %.8e, blue %.8e stub!\n", iface, red, green, blue);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMZBUFFERMODE WINAPI d3drm_frame3_GetZbufferMode(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return D3DRMZBUFFER_FROMPARENT;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetMaterialMode(IDirect3DRMFrame3 *iface, D3DRMMATERIALMODE mode)
+{
+    FIXME("iface %p, mode %#x stub!\n", iface, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetOrientation(IDirect3DRMFrame3 *iface, IDirect3DRMFrame3 *reference,
+        D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, D3DVALUE ux, D3DVALUE uy, D3DVALUE uz)
+{
+    FIXME("iface %p, reference %p, dx %.8e, dy %.8e, dz %.8e, ux %.8e, uy %.8e, uz %.8e stub!\n",
+            iface, reference, dx, dy, dz, ux, uy, uz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetPosition(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, reference %p, x %.8e, y %.8e, z %.8e stub!\n", iface, reference, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetRotation(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta)
+{
+    FIXME("iface %p, reference %p, x %.8e, y %.8e, z %.8e, theta %.8e stub!\n",
+            iface, reference, x, y, z, theta);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSortMode(IDirect3DRMFrame3 *iface, D3DRMSORTMODE mode)
+{
+    FIXME("iface %p, mode %#x stub!\n", iface, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetTexture(IDirect3DRMFrame3 *iface, IDirect3DRMTexture3 *texture)
+{
+    FIXME("iface %p, texture %p stub!\n", iface, texture);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetVelocity(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, BOOL with_rotation)
+{
+    FIXME("iface %p, reference %p, x %.8e, y %.8e, z %.8e, with_rotation %#x.\n",
+            iface, reference, x, y, z, with_rotation);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetZbufferMode(IDirect3DRMFrame3 *iface, D3DRMZBUFFERMODE mode)
+{
+    FIXME("iface %p, mode %#x stub!\n", iface, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_Transform(IDirect3DRMFrame3 *iface, D3DVECTOR *d, D3DVECTOR *s)
+{
+    FIXME("iface %p, d %p, s %p stub!\n", iface, d, s);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetBox(IDirect3DRMFrame3 *iface, D3DRMBOX *box)
+{
+    FIXME("iface %p, box %p stub!\n", iface, box);
+
+    return E_NOTIMPL;
+}
+
+static BOOL WINAPI d3drm_frame3_GetBoxEnable(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetAxes(IDirect3DRMFrame3 *iface, D3DVECTOR *dir, D3DVECTOR *up)
+{
+    FIXME("iface %p, dir %p, up %p stub!\n", iface, dir, up);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetMaterial(IDirect3DRMFrame3 *iface, IDirect3DRMMaterial2 **material)
+{
+    FIXME("iface %p, material %p stub!\n", iface, material);
+
+    return E_NOTIMPL;
+}
+
+static BOOL WINAPI d3drm_frame3_GetInheritAxes(IDirect3DRMFrame3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetHierarchyBox(IDirect3DRMFrame3 *iface, D3DRMBOX *box)
+{
+    FIXME("iface %p, box %p stub!\n", iface, box);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetBox(IDirect3DRMFrame3 *iface, D3DRMBOX *box)
+{
+    FIXME("iface %p, box %p stub!\n", iface, box);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetBoxEnable(IDirect3DRMFrame3 *iface, BOOL enable)
+{
+    FIXME("iface %p, enable %#x stub!\n", iface, enable);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetAxes(IDirect3DRMFrame3 *iface,
+        D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, D3DVALUE ux, D3DVALUE uy, D3DVALUE uz)
+{
+    FIXME("iface %p, dx %.8e, dy %.8e, dz %.8e, ux %.8e, uy %.8e, uz %.8e stub!\n",
+            iface, dx, dy, dz, ux, uy, uz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetInheritAxes(IDirect3DRMFrame3 *iface, BOOL inherit)
+{
+    FIXME("iface %p, inherit %#x stub!\n", iface, inherit);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetMaterial(IDirect3DRMFrame3 *iface, IDirect3DRMMaterial2 *material)
+{
+    FIXME("iface %p, material %p stub!\n", iface, material);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetQuaternion(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, D3DRMQUATERNION *q)
+{
+    FIXME("iface %p, reference %p, q %p stub!\n", iface, reference, q);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_RayPick(IDirect3DRMFrame3 *iface, IDirect3DRMFrame3 *reference,
+        D3DRMRAY *ray, DWORD flags, IDirect3DRMPicked2Array **visuals)
+{
+    FIXME("iface %p, reference %p, ray %p, flags %#x, visuals %p stub!\n",
+            iface, reference, ray, flags, visuals);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_Save(IDirect3DRMFrame3 *iface,
+        const char *filename, D3DRMXOFFORMAT format, D3DRMSAVEOPTIONS flags)
+{
+    FIXME("iface %p, filename %s, format %#x, flags %#x stub!\n",
+            iface, debugstr_a(filename), format, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_TransformVectors(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, DWORD num, D3DVECTOR *dst, D3DVECTOR *src)
+{
+    FIXME("iface %p, reference %p, num %u, dst %p, src %p stub!\n", iface, reference, num, dst, src);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_InverseTransformVectors(IDirect3DRMFrame3 *iface,
+        IDirect3DRMFrame3 *reference, DWORD num, D3DVECTOR *dst, D3DVECTOR *src)
+{
+    FIXME("iface %p, reference %p, num %u, dst %p, src %p stub!\n", iface, reference, num, dst, src);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetTraversalOptions(IDirect3DRMFrame3 *iface, DWORD flags)
+{
+    FIXME("iface %p, flags %#x stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetTraversalOptions(IDirect3DRMFrame3 *iface, DWORD *flags)
+{
+    FIXME("iface %p, flags %p stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetSceneFogMethod(IDirect3DRMFrame3 *iface, DWORD flags)
+{
+    FIXME("iface %p, flags %#x stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetSceneFogMethod(IDirect3DRMFrame3 *iface, DWORD *fog_mode)
+{
+    FIXME("iface %p, fog_mode %p stub!\n", iface, fog_mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_SetMaterialOverride(IDirect3DRMFrame3 *iface,
+        D3DRMMATERIALOVERRIDE *override)
+{
+    FIXME("iface %p, override %p stub!\n", iface, override);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_frame3_GetMaterialOverride(IDirect3DRMFrame3 *iface,
+        D3DRMMATERIALOVERRIDE *override)
+{
+    FIXME("iface %p, override %p stub!\n", iface, override);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMFrame3Vtbl d3drm_frame3_vtbl =
+{
+    d3drm_frame3_QueryInterface,
+    d3drm_frame3_AddRef,
+    d3drm_frame3_Release,
+    d3drm_frame3_Clone,
+    d3drm_frame3_AddDestroyCallback,
+    d3drm_frame3_DeleteDestroyCallback,
+    d3drm_frame3_SetAppData,
+    d3drm_frame3_GetAppData,
+    d3drm_frame3_SetName,
+    d3drm_frame3_GetName,
+    d3drm_frame3_GetClassName,
+    d3drm_frame3_AddChild,
+    d3drm_frame3_AddLight,
+    d3drm_frame3_AddMoveCallback,
+    d3drm_frame3_AddTransform,
+    d3drm_frame3_AddTranslation,
+    d3drm_frame3_AddScale,
+    d3drm_frame3_AddRotation,
+    d3drm_frame3_AddVisual,
+    d3drm_frame3_GetChildren,
+    d3drm_frame3_GetColor,
+    d3drm_frame3_GetLights,
+    d3drm_frame3_GetMaterialMode,
+    d3drm_frame3_GetParent,
+    d3drm_frame3_GetPosition,
+    d3drm_frame3_GetRotation,
+    d3drm_frame3_GetScene,
+    d3drm_frame3_GetSortMode,
+    d3drm_frame3_GetTexture,
+    d3drm_frame3_GetTransform,
+    d3drm_frame3_GetVelocity,
+    d3drm_frame3_GetOrientation,
+    d3drm_frame3_GetVisuals,
+    d3drm_frame3_InverseTransform,
+    d3drm_frame3_Load,
+    d3drm_frame3_LookAt,
+    d3drm_frame3_Move,
+    d3drm_frame3_DeleteChild,
+    d3drm_frame3_DeleteLight,
+    d3drm_frame3_DeleteMoveCallback,
+    d3drm_frame3_DeleteVisual,
+    d3drm_frame3_GetSceneBackground,
+    d3drm_frame3_GetSceneBackgroundDepth,
+    d3drm_frame3_GetSceneFogColor,
+    d3drm_frame3_GetSceneFogEnable,
+    d3drm_frame3_GetSceneFogMode,
+    d3drm_frame3_GetSceneFogParams,
+    d3drm_frame3_SetSceneBackground,
+    d3drm_frame3_SetSceneBackgroundRGB,
+    d3drm_frame3_SetSceneBackgroundDepth,
+    d3drm_frame3_SetSceneBackgroundImage,
+    d3drm_frame3_SetSceneFogEnable,
+    d3drm_frame3_SetSceneFogColor,
+    d3drm_frame3_SetSceneFogMode,
+    d3drm_frame3_SetSceneFogParams,
+    d3drm_frame3_SetColor,
+    d3drm_frame3_SetColorRGB,
+    d3drm_frame3_GetZbufferMode,
+    d3drm_frame3_SetMaterialMode,
+    d3drm_frame3_SetOrientation,
+    d3drm_frame3_SetPosition,
+    d3drm_frame3_SetRotation,
+    d3drm_frame3_SetSortMode,
+    d3drm_frame3_SetTexture,
+    d3drm_frame3_SetVelocity,
+    d3drm_frame3_SetZbufferMode,
+    d3drm_frame3_Transform,
+    d3drm_frame3_GetBox,
+    d3drm_frame3_GetBoxEnable,
+    d3drm_frame3_GetAxes,
+    d3drm_frame3_GetMaterial,
+    d3drm_frame3_GetInheritAxes,
+    d3drm_frame3_GetHierarchyBox,
+    d3drm_frame3_SetBox,
+    d3drm_frame3_SetBoxEnable,
+    d3drm_frame3_SetAxes,
+    d3drm_frame3_SetInheritAxes,
+    d3drm_frame3_SetMaterial,
+    d3drm_frame3_SetQuaternion,
+    d3drm_frame3_RayPick,
+    d3drm_frame3_Save,
+    d3drm_frame3_TransformVectors,
+    d3drm_frame3_InverseTransformVectors,
+    d3drm_frame3_SetTraversalOptions,
+    d3drm_frame3_GetTraversalOptions,
+    d3drm_frame3_SetSceneFogMethod,
+    d3drm_frame3_GetSceneFogMethod,
+    d3drm_frame3_SetMaterialOverride,
+    d3drm_frame3_GetMaterialOverride,
+};
+
+static inline struct d3drm_frame *unsafe_impl_from_IDirect3DRMFrame3(IDirect3DRMFrame3 *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d3drm_frame3_vtbl);
+
+    return impl_from_IDirect3DRMFrame3(iface);
+}
+
+HRESULT Direct3DRMFrame_create(REFIID riid, IUnknown *parent, IUnknown **out)
+{
+    struct d3drm_frame *object;
+    HRESULT hr;
+
+    TRACE("riid %s, parent %p, out %p.\n", debugstr_guid(riid), parent, out);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMFrame2_iface.lpVtbl = &d3drm_frame2_vtbl;
+    object->IDirect3DRMFrame3_iface.lpVtbl = &d3drm_frame3_vtbl;
+    object->ref = 1;
+    object->scenebackground = RGBA_MAKE(0, 0, 0, 0xff);
+
+    memcpy(object->transform, identity, sizeof(D3DRMMATRIX4D));
+
+    if (parent)
+    {
+        IDirect3DRMFrame3 *p;
+
+        hr = IDirect3DRMFrame_QueryInterface(parent, &IID_IDirect3DRMFrame3, (void**)&p);
+        if (hr != S_OK)
+        {
+            HeapFree(GetProcessHeap(), 0, object);
+            return hr;
+        }
+        IDirect3DRMFrame_Release(parent);
+        IDirect3DRMFrame3_AddChild(p, &object->IDirect3DRMFrame3_iface);
+    }
+
+    hr = IDirect3DRMFrame3_QueryInterface(&object->IDirect3DRMFrame3_iface, riid, (void **)out);
+    IDirect3DRMFrame3_Release(&object->IDirect3DRMFrame3_iface);
+    return S_OK;
+}
diff --git a/reactos/dll/directx/wine/d3drm/light.c b/reactos/dll/directx/wine/d3drm/light.c
new file mode 100644 (file)
index 0000000..4145ee1
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Implementation of IDirect3DRMLight Interface
+ *
+ * Copyright 2012 André Hentschel
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+struct d3drm_light
+{
+    IDirect3DRMLight IDirect3DRMLight_iface;
+    LONG ref;
+    D3DRMLIGHTTYPE type;
+    D3DCOLOR color;
+    D3DVALUE range;
+    D3DVALUE cattenuation;
+    D3DVALUE lattenuation;
+    D3DVALUE qattenuation;
+    D3DVALUE umbra;
+    D3DVALUE penumbra;
+};
+
+static inline struct d3drm_light *impl_from_IDirect3DRMLight(IDirect3DRMLight *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_light, IDirect3DRMLight_iface);
+}
+
+static HRESULT WINAPI d3drm_light_QueryInterface(IDirect3DRMLight *iface, REFIID riid, void **out)
+{
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMLight)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        IDirect3DRMLight_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI d3drm_light_AddRef(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+    ULONG refcount = InterlockedIncrement(&light->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_light_Release(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+    ULONG refcount = InterlockedDecrement(&light->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+        HeapFree(GetProcessHeap(), 0, light);
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_light_Clone(IDirect3DRMLight *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_light_AddDestroyCallback(IDirect3DRMLight *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_light_DeleteDestroyCallback(IDirect3DRMLight *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_light_SetAppData(IDirect3DRMLight *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_light_GetAppData(IDirect3DRMLight *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_light_SetName(IDirect3DRMLight *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_light_GetName(IDirect3DRMLight *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_light_GetClassName(IDirect3DRMLight *iface, DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Light") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Light");
+    *size = sizeof("Light");
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetType(IDirect3DRMLight *iface, D3DRMLIGHTTYPE type)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, type %#x.\n", iface, type);
+
+    light->type = type;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetColor(IDirect3DRMLight *iface, D3DCOLOR color)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, color 0x%08x.\n", iface, color);
+
+    light->color = color;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetColorRGB(IDirect3DRMLight *iface,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, red %.8e, green %.8e, blue %.8e.\n", iface, red, green, blue);
+
+    light->color = RGBA_MAKE((BYTE)(red * 255.0f), (BYTE)(green * 255.0f), (BYTE)(blue * 255.0f), 0xff);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetRange(IDirect3DRMLight *iface, D3DVALUE range)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, range %.8e.\n", iface, range);
+
+    light->range = range;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetUmbra(IDirect3DRMLight *iface, D3DVALUE umbra)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, umbra %.8e.\n", iface, umbra);
+
+    light->umbra = umbra;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetPenumbra(IDirect3DRMLight *iface, D3DVALUE penumbra)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, penumbra %.8e.\n", iface, penumbra);
+
+    light->penumbra = penumbra;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetConstantAttenuation(IDirect3DRMLight *iface, D3DVALUE attenuation)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, attenuation %.8e.\n", iface, attenuation);
+
+    light->cattenuation = attenuation;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetLinearAttenuation(IDirect3DRMLight *iface, D3DVALUE attenuation)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, attenuation %.8e.\n", iface, attenuation);
+
+    light->lattenuation = attenuation;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_light_SetQuadraticAttenuation(IDirect3DRMLight *iface, D3DVALUE attenuation)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p, attenuation %.8e.\n", iface, attenuation);
+
+    light->qattenuation = attenuation;
+
+    return D3DRM_OK;
+}
+
+static D3DVALUE WINAPI d3drm_light_GetRange(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return light->range;
+}
+
+static D3DVALUE WINAPI d3drm_light_GetUmbra(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p.\n", light);
+
+    return light->umbra;
+}
+
+static D3DVALUE WINAPI d3drm_light_GetPenumbra(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return light->penumbra;
+}
+
+static D3DVALUE WINAPI d3drm_light_GetConstantAttenuation(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return light->cattenuation;
+}
+
+static D3DVALUE WINAPI d3drm_light_GetLinearAttenuation(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return light->lattenuation;
+}
+
+static D3DVALUE WINAPI d3drm_light_GetQuadraticAttenuation(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return light->qattenuation;
+}
+
+static D3DCOLOR WINAPI d3drm_light_GetColor(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return light->color;
+}
+
+static D3DRMLIGHTTYPE WINAPI d3drm_light_GetType(IDirect3DRMLight *iface)
+{
+    struct d3drm_light *light = impl_from_IDirect3DRMLight(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return light->type;
+}
+
+static HRESULT WINAPI d3drm_light_SetEnableFrame(IDirect3DRMLight *iface, IDirect3DRMFrame *frame)
+{
+    FIXME("iface %p, frame %p stub!\n", iface, frame);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_light_GetEnableFrame(IDirect3DRMLight *iface, IDirect3DRMFrame **frame)
+{
+    FIXME("iface %p, frame %p stub!\n", iface, frame);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMLightVtbl d3drm_light_vtbl =
+{
+    d3drm_light_QueryInterface,
+    d3drm_light_AddRef,
+    d3drm_light_Release,
+    d3drm_light_Clone,
+    d3drm_light_AddDestroyCallback,
+    d3drm_light_DeleteDestroyCallback,
+    d3drm_light_SetAppData,
+    d3drm_light_GetAppData,
+    d3drm_light_SetName,
+    d3drm_light_GetName,
+    d3drm_light_GetClassName,
+    d3drm_light_SetType,
+    d3drm_light_SetColor,
+    d3drm_light_SetColorRGB,
+    d3drm_light_SetRange,
+    d3drm_light_SetUmbra,
+    d3drm_light_SetPenumbra,
+    d3drm_light_SetConstantAttenuation,
+    d3drm_light_SetLinearAttenuation,
+    d3drm_light_SetQuadraticAttenuation,
+    d3drm_light_GetRange,
+    d3drm_light_GetUmbra,
+    d3drm_light_GetPenumbra,
+    d3drm_light_GetConstantAttenuation,
+    d3drm_light_GetLinearAttenuation,
+    d3drm_light_GetQuadraticAttenuation,
+    d3drm_light_GetColor,
+    d3drm_light_GetType,
+    d3drm_light_SetEnableFrame,
+    d3drm_light_GetEnableFrame,
+};
+
+HRESULT Direct3DRMLight_create(IUnknown **out)
+{
+    struct d3drm_light *object;
+
+    TRACE("out %p.\n", out);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMLight_iface.lpVtbl = &d3drm_light_vtbl;
+    object->ref = 1;
+
+    *out = (IUnknown *)&object->IDirect3DRMLight_iface;
+
+    return S_OK;
+}
diff --git a/reactos/dll/directx/wine/d3drm/material.c b/reactos/dll/directx/wine/d3drm/material.c
new file mode 100644 (file)
index 0000000..4e6fa27
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Implementation of IDirect3DRMMaterial2 interface
+ *
+ * Copyright 2012 Christian Costa
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+struct color_rgb
+{
+    D3DVALUE r;
+    D3DVALUE g;
+    D3DVALUE b;
+};
+
+struct d3drm_material
+{
+    IDirect3DRMMaterial2 IDirect3DRMMaterial2_iface;
+    LONG ref;
+    struct color_rgb emissive;
+    struct color_rgb specular;
+    D3DVALUE power;
+    struct color_rgb ambient;
+};
+
+static inline struct d3drm_material *impl_from_IDirect3DRMMaterial2(IDirect3DRMMaterial2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_material, IDirect3DRMMaterial2_iface);
+}
+
+static HRESULT WINAPI d3drm_material_QueryInterface(IDirect3DRMMaterial2 *iface, REFIID riid, void **out)
+{
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMMaterial2)
+            || IsEqualGUID(riid, &IID_IDirect3DRMMaterial)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        IDirect3DRMMaterial2_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI d3drm_material_AddRef(IDirect3DRMMaterial2 *iface)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+    ULONG refcount = InterlockedIncrement(&material->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_material_Release(IDirect3DRMMaterial2 *iface)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+    ULONG refcount = InterlockedDecrement(&material->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+        HeapFree(GetProcessHeap(), 0, material);
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_material_Clone(IDirect3DRMMaterial2 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_material_AddDestroyCallback(IDirect3DRMMaterial2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_material_DeleteDestroyCallback(IDirect3DRMMaterial2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_material_SetAppData(IDirect3DRMMaterial2 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_material_GetAppData(IDirect3DRMMaterial2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_material_SetName(IDirect3DRMMaterial2 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_material_GetName(IDirect3DRMMaterial2 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_material_GetClassName(IDirect3DRMMaterial2 *iface, DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Material") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Material");
+    *size = sizeof("Material");
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_material_SetPower(IDirect3DRMMaterial2 *iface, D3DVALUE power)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+
+    TRACE("iface %p, power %.8e.\n", iface, power);
+
+    material->power = power;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_material_SetSpecular(IDirect3DRMMaterial2 *iface,
+        D3DVALUE r, D3DVALUE g, D3DVALUE b)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+
+    TRACE("iface %p, r %.8e, g %.8e, b %.8e.\n", iface, r, g, b);
+
+    material->specular.r = r;
+    material->specular.g = g;
+    material->specular.b = b;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_material_SetEmissive(IDirect3DRMMaterial2 *iface,
+        D3DVALUE r, D3DVALUE g, D3DVALUE b)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+
+    TRACE("iface %p, r %.8e, g %.8e, b %.8e.\n", iface, r, g, b);
+
+    material->emissive.r = r;
+    material->emissive.g = g;
+    material->emissive.b = b;
+
+    return D3DRM_OK;
+}
+
+static D3DVALUE WINAPI d3drm_material_GetPower(IDirect3DRMMaterial2 *iface)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return material->power;
+}
+
+static HRESULT WINAPI d3drm_material_GetSpecular(IDirect3DRMMaterial2 *iface,
+        D3DVALUE *r, D3DVALUE *g, D3DVALUE *b)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+
+    TRACE("iface %p, r %p, g %p, b %p.\n", iface, r, g, b);
+
+    *r = material->specular.r;
+    *g = material->specular.g;
+    *b = material->specular.b;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_material_GetEmissive(IDirect3DRMMaterial2 *iface,
+        D3DVALUE *r, D3DVALUE *g, D3DVALUE *b)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+
+    TRACE("iface %p, r %p, g %p, b %p.\n", iface, r, g, b);
+
+    *r = material->emissive.r;
+    *g = material->emissive.g;
+    *b = material->emissive.b;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_material_GetAmbient(IDirect3DRMMaterial2 *iface,
+        D3DVALUE *r, D3DVALUE *g, D3DVALUE *b)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+
+    TRACE("iface %p, r %p, g %p, b %p.\n", iface, r, g, b);
+
+    *r = material->ambient.r;
+    *g = material->ambient.g;
+    *b = material->ambient.b;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_material_SetAmbient(IDirect3DRMMaterial2 *iface,
+        D3DVALUE r, D3DVALUE g, D3DVALUE b)
+{
+    struct d3drm_material *material = impl_from_IDirect3DRMMaterial2(iface);
+
+    TRACE("iface %p, r %.8e, g %.8e, b %.8e.\n", iface, r, g, b);
+
+    material->ambient.r = r;
+    material->ambient.g = g;
+    material->ambient.b = b;
+
+    return D3DRM_OK;
+}
+
+static const struct IDirect3DRMMaterial2Vtbl d3drm_material_vtbl =
+{
+    d3drm_material_QueryInterface,
+    d3drm_material_AddRef,
+    d3drm_material_Release,
+    d3drm_material_Clone,
+    d3drm_material_AddDestroyCallback,
+    d3drm_material_DeleteDestroyCallback,
+    d3drm_material_SetAppData,
+    d3drm_material_GetAppData,
+    d3drm_material_SetName,
+    d3drm_material_GetName,
+    d3drm_material_GetClassName,
+    d3drm_material_SetPower,
+    d3drm_material_SetSpecular,
+    d3drm_material_SetEmissive,
+    d3drm_material_GetPower,
+    d3drm_material_GetSpecular,
+    d3drm_material_GetEmissive,
+    d3drm_material_GetAmbient,
+    d3drm_material_SetAmbient,
+};
+
+HRESULT Direct3DRMMaterial_create(IDirect3DRMMaterial2 **out)
+{
+    struct d3drm_material *object;
+
+    TRACE("out %p.\n", out);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMMaterial2_iface.lpVtbl = &d3drm_material_vtbl;
+    object->ref = 1;
+
+    object->specular.r = 1.0f;
+    object->specular.g = 1.0f;
+    object->specular.b = 1.0f;
+
+    *out = &object->IDirect3DRMMaterial2_iface;
+
+    return S_OK;
+}
diff --git a/reactos/dll/directx/wine/d3drm/math.c b/reactos/dll/directx/wine/d3drm/math.c
new file mode 100644 (file)
index 0000000..698e222
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2007 David Adam
+ * Copyright 2007 Vijay Kiran Kamuju
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+#include <math.h>
+
+/* Create a RGB color from its components */
+D3DCOLOR WINAPI D3DRMCreateColorRGB(D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    return (D3DRMCreateColorRGBA(red, green, blue, 255.0));
+}
+/* Create a RGBA color from its components */
+D3DCOLOR WINAPI D3DRMCreateColorRGBA(D3DVALUE red, D3DVALUE green, D3DVALUE blue, D3DVALUE alpha)
+{
+    int Red, Green, Blue, Alpha;
+    Red=floor(red*255);
+    Green=floor(green*255);
+    Blue=floor(blue*255);
+    Alpha=floor(alpha*255);
+    if (red < 0) Red=0;
+    if (red > 1) Red=255;
+    if (green < 0) Green=0;
+    if (green > 1) Green=255;
+    if (blue < 0) Blue=0;
+    if (blue > 1) Blue=255;
+    if (alpha < 0) Alpha=0;
+    if (alpha > 1) Alpha=255;
+    return (RGBA_MAKE(Red, Green, Blue, Alpha));
+}
+
+/* Determine the alpha part of a color */
+D3DVALUE WINAPI D3DRMColorGetAlpha(D3DCOLOR color)
+{
+    return (RGBA_GETALPHA(color)/255.0);
+}
+
+/* Determine the blue part of a color */
+D3DVALUE WINAPI D3DRMColorGetBlue(D3DCOLOR color)
+{
+    return (RGBA_GETBLUE(color)/255.0);
+}
+
+/* Determine the green part of a color */
+D3DVALUE WINAPI D3DRMColorGetGreen(D3DCOLOR color)
+{
+    return (RGBA_GETGREEN(color)/255.0);
+}
+
+/* Determine the red part of a color */
+D3DVALUE WINAPI D3DRMColorGetRed(D3DCOLOR color)
+{
+    return (RGBA_GETRED(color)/255.0);
+}
+
+/* Product of 2 quaternions */
+D3DRMQUATERNION * WINAPI D3DRMQuaternionMultiply(D3DRMQUATERNION *q, D3DRMQUATERNION *a, D3DRMQUATERNION *b)
+{
+    D3DRMQUATERNION temp;
+    D3DVECTOR cross_product;
+
+    D3DRMVectorCrossProduct(&cross_product, &a->v, &b->v);
+    temp.s = a->s * b->s - D3DRMVectorDotProduct(&a->v, &b->v);
+    temp.v.u1.x = a->s * b->v.u1.x + b->s * a->v.u1.x + cross_product.u1.x;
+    temp.v.u2.y = a->s * b->v.u2.y + b->s * a->v.u2.y + cross_product.u2.y;
+    temp.v.u3.z = a->s * b->v.u3.z + b->s * a->v.u3.z + cross_product.u3.z;
+
+    *q = temp;
+    return q;
+}
+
+/* Matrix for the Rotation that a unit quaternion represents */
+void WINAPI D3DRMMatrixFromQuaternion(D3DRMMATRIX4D m, D3DRMQUATERNION *q)
+{
+    D3DVALUE w,x,y,z;
+    w = q->s;
+    x = q->v.u1.x;
+    y = q->v.u2.y;
+    z = q->v.u3.z;
+    m[0][0] = 1.0-2.0*(y*y+z*z);
+    m[1][1] = 1.0-2.0*(x*x+z*z);
+    m[2][2] = 1.0-2.0*(x*x+y*y);
+    m[1][0] = 2.0*(x*y+z*w);
+    m[0][1] = 2.0*(x*y-z*w);
+    m[2][0] = 2.0*(x*z-y*w);
+    m[0][2] = 2.0*(x*z+y*w);
+    m[2][1] = 2.0*(y*z+x*w);
+    m[1][2] = 2.0*(y*z-x*w);
+    m[3][0] = 0.0;
+    m[3][1] = 0.0;
+    m[3][2] = 0.0;
+    m[0][3] = 0.0;
+    m[1][3] = 0.0;
+    m[2][3] = 0.0;
+    m[3][3] = 1.0;
+}
+
+/* Return a unit quaternion that represents a rotation of an angle around an axis */
+D3DRMQUATERNION * WINAPI D3DRMQuaternionFromRotation(D3DRMQUATERNION *q, D3DVECTOR *v, D3DVALUE theta)
+{
+    q->s = cos(theta/2.0);
+    D3DRMVectorScale(&q->v, D3DRMVectorNormalize(v), sin(theta/2.0));
+    return q;
+}
+
+/* Interpolation between two quaternions */
+D3DRMQUATERNION * WINAPI D3DRMQuaternionSlerp(D3DRMQUATERNION *q,
+        D3DRMQUATERNION *a, D3DRMQUATERNION *b, D3DVALUE alpha)
+{
+    D3DVALUE dot, epsilon, temp, theta, u;
+    D3DVECTOR v1, v2;
+
+    dot = a->s * b->s + D3DRMVectorDotProduct(&a->v, &b->v);
+    epsilon = 1.0f;
+    temp = 1.0f - alpha;
+    u = alpha;
+    if (dot < 0.0)
+    {
+     epsilon = -1.0;
+     dot = -dot;
+    }
+    if( 1.0f - dot > 0.001f )
+    {
+        theta = acos(dot);
+        temp  = sin(theta * temp) / sin(theta);
+        u = sin(theta * alpha) / sin(theta);
+    }
+    q->s = temp * a->s + epsilon * u * b->s;
+    D3DRMVectorScale(&v1, &a->v, temp);
+    D3DRMVectorScale(&v2, &b->v, epsilon * u);
+    D3DRMVectorAdd(&q->v, &v1, &v2);
+    return q;
+}
+
+/* Add Two Vectors */
+D3DVECTOR * WINAPI D3DRMVectorAdd(D3DVECTOR *d, D3DVECTOR *s1, D3DVECTOR *s2)
+{
+    D3DVECTOR temp;
+
+    temp.u1.x=s1->u1.x + s2->u1.x;
+    temp.u2.y=s1->u2.y + s2->u2.y;
+    temp.u3.z=s1->u3.z + s2->u3.z;
+
+    *d = temp;
+    return d;
+}
+
+/* Subtract Two Vectors */
+D3DVECTOR * WINAPI D3DRMVectorSubtract(D3DVECTOR *d, D3DVECTOR *s1, D3DVECTOR *s2)
+{
+    D3DVECTOR temp;
+
+    temp.u1.x=s1->u1.x - s2->u1.x;
+    temp.u2.y=s1->u2.y - s2->u2.y;
+    temp.u3.z=s1->u3.z - s2->u3.z;
+
+    *d = temp;
+    return d;
+}
+
+/* Cross Product of Two Vectors */
+D3DVECTOR * WINAPI D3DRMVectorCrossProduct(D3DVECTOR *d, D3DVECTOR *s1, D3DVECTOR *s2)
+{
+    D3DVECTOR temp;
+
+    temp.u1.x=s1->u2.y * s2->u3.z - s1->u3.z * s2->u2.y;
+    temp.u2.y=s1->u3.z * s2->u1.x - s1->u1.x * s2->u3.z;
+    temp.u3.z=s1->u1.x * s2->u2.y - s1->u2.y * s2->u1.x;
+
+    *d = temp;
+    return d;
+}
+
+/* Dot Product of Two vectors */
+D3DVALUE WINAPI D3DRMVectorDotProduct(D3DVECTOR *s1, D3DVECTOR *s2)
+{
+    D3DVALUE dot_product;
+    dot_product=s1->u1.x * s2->u1.x + s1->u2.y * s2->u2.y + s1->u3.z * s2->u3.z;
+    return dot_product;
+}
+
+/* Norm of a vector */
+D3DVALUE WINAPI D3DRMVectorModulus(D3DVECTOR *v)
+{
+    D3DVALUE result;
+    result=sqrt(v->u1.x * v->u1.x + v->u2.y * v->u2.y + v->u3.z * v->u3.z);
+    return result;
+}
+
+/* Normalize a vector.  Returns (1,0,0) if INPUT is the NULL vector. */
+D3DVECTOR * WINAPI D3DRMVectorNormalize(D3DVECTOR *u)
+{
+    D3DVALUE modulus = D3DRMVectorModulus(u);
+    if(modulus)
+    {
+        D3DRMVectorScale(u,u,1.0/modulus);
+    }
+    else
+    {
+        u->u1.x=1.0;
+        u->u2.y=0.0;
+        u->u3.z=0.0;
+    }
+    return u;
+}
+
+/* Returns a random unit vector */
+D3DVECTOR * WINAPI D3DRMVectorRandom(D3DVECTOR *d)
+{
+    d->u1.x = rand();
+    d->u2.y = rand();
+    d->u3.z = rand();
+    D3DRMVectorNormalize(d);
+    return d;
+}
+
+/* Reflection of a vector on a surface */
+D3DVECTOR * WINAPI D3DRMVectorReflect(D3DVECTOR *r, D3DVECTOR *ray, D3DVECTOR *norm)
+{
+    D3DVECTOR sca, temp;
+    D3DRMVectorSubtract(&temp, D3DRMVectorScale(&sca, norm, 2.0*D3DRMVectorDotProduct(ray,norm)), ray);
+
+    *r = temp;
+    return r;
+}
+
+/* Rotation of a vector */
+D3DVECTOR * WINAPI D3DRMVectorRotate(D3DVECTOR *r, D3DVECTOR *v, D3DVECTOR *axis, D3DVALUE theta)
+{
+    D3DRMQUATERNION quaternion1, quaternion2, quaternion3;
+    D3DVECTOR norm;
+
+    quaternion1.s = cos(theta * 0.5f);
+    quaternion2.s = cos(theta * 0.5f);
+    norm = *D3DRMVectorNormalize(axis);
+    D3DRMVectorScale(&quaternion1.v, &norm, sin(theta * 0.5f));
+    D3DRMVectorScale(&quaternion2.v, &norm, -sin(theta * 0.5f));
+    quaternion3.s = 0.0;
+    quaternion3.v = *v;
+    D3DRMQuaternionMultiply(&quaternion1, &quaternion1, &quaternion3);
+    D3DRMQuaternionMultiply(&quaternion1, &quaternion1, &quaternion2);
+
+    *r = *D3DRMVectorNormalize(&quaternion1.v);
+    return r;
+}
+
+/* Scale a vector */
+D3DVECTOR * WINAPI D3DRMVectorScale(D3DVECTOR *d, D3DVECTOR *s, D3DVALUE factor)
+{
+    D3DVECTOR temp;
+
+    temp.u1.x=factor * s->u1.x;
+    temp.u2.y=factor * s->u2.y;
+    temp.u3.z=factor * s->u3.z;
+
+    *d = temp;
+    return d;
+}
diff --git a/reactos/dll/directx/wine/d3drm/meshbuilder.c b/reactos/dll/directx/wine/d3drm/meshbuilder.c
new file mode 100644 (file)
index 0000000..7f5ae7f
--- /dev/null
@@ -0,0 +1,2810 @@
+/*
+ * Implementation of IDirect3DRMMeshBuilderX and IDirect3DRMMesh interfaces
+ *
+ * Copyright 2010, 2012 Christian Costa
+ * Copyright 2011 André Hentschel
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+struct mesh_group
+{
+    unsigned nb_vertices;
+    D3DRMVERTEX* vertices;
+    unsigned nb_faces;
+    unsigned vertex_per_face;
+    DWORD face_data_size;
+    unsigned* face_data;
+    D3DCOLOR color;
+    IDirect3DRMMaterial2* material;
+    IDirect3DRMTexture3* texture;
+};
+
+struct d3drm_mesh
+{
+    IDirect3DRMMesh IDirect3DRMMesh_iface;
+    LONG ref;
+    DWORD groups_capacity;
+    DWORD nb_groups;
+    struct mesh_group *groups;
+};
+
+struct coords_2d
+{
+    D3DVALUE u;
+    D3DVALUE v;
+};
+
+struct mesh_material
+{
+    D3DCOLOR color;
+    IDirect3DRMMaterial2 *material;
+    IDirect3DRMTexture3 *texture;
+};
+
+struct d3drm_mesh_builder
+{
+    IDirect3DRMMeshBuilder2 IDirect3DRMMeshBuilder2_iface;
+    IDirect3DRMMeshBuilder3 IDirect3DRMMeshBuilder3_iface;
+    LONG ref;
+    char* name;
+    DWORD nb_vertices;
+    D3DVECTOR* pVertices;
+    DWORD nb_normals;
+    D3DVECTOR* pNormals;
+    DWORD nb_faces;
+    DWORD face_data_size;
+    void *pFaceData;
+    DWORD nb_coords2d;
+    struct coords_2d *pCoords2d;
+    D3DCOLOR color;
+    IDirect3DRMMaterial2 *material;
+    IDirect3DRMTexture3 *texture;
+    DWORD nb_materials;
+    struct mesh_material *materials;
+    DWORD *material_indices;
+};
+
+char templates[] = {
+"xof 0302txt 0064"
+"template Header"
+"{"
+"<3D82AB43-62DA-11CF-AB39-0020AF71E433>"
+"WORD major;"
+"WORD minor;"
+"DWORD flags;"
+"}"
+"template Vector"
+"{"
+"<3D82AB5E-62DA-11CF-AB39-0020AF71E433>"
+"FLOAT x;"
+"FLOAT y;"
+"FLOAT z;"
+"}"
+"template Coords2d"
+"{"
+"<F6F23F44-7686-11CF-8F52-0040333594A3>"
+"FLOAT u;"
+"FLOAT v;"
+"}"
+"template Matrix4x4"
+"{"
+"<F6F23F45-7686-11CF-8F52-0040333594A3>"
+"array FLOAT matrix[16];"
+"}"
+"template ColorRGBA"
+"{"
+"<35FF44E0-6C7C-11CF-8F52-0040333594A3>"
+"FLOAT red;"
+"FLOAT green;"
+"FLOAT blue;"
+"FLOAT alpha;"
+"}"
+"template ColorRGB"
+"{"
+"<D3E16E81-7835-11CF-8F52-0040333594A3>"
+"FLOAT red;"
+"FLOAT green;"
+"FLOAT blue;"
+"}"
+"template IndexedColor"
+"{"
+"<1630B820-7842-11CF-8F52-0040333594A3>"
+"DWORD index;"
+"ColorRGBA indexColor;"
+"}"
+"template Boolean"
+"{"
+"<537DA6A0-CA37-11D0-941C-0080C80CFA7B>"
+"DWORD truefalse;"
+"}"
+"template Boolean2d"
+"{"
+"<4885AE63-78E8-11CF-8F52-0040333594A3>"
+"Boolean u;"
+"Boolean v;"
+"}"
+"template MaterialWrap"
+"{"
+"<4885AE60-78E8-11CF-8F52-0040333594A3>"
+"Boolean u;"
+"Boolean v;"
+"}"
+"template TextureFilename"
+"{"
+"<A42790E1-7810-11CF-8F52-0040333594A3>"
+"STRING filename;"
+"}"
+"template Material"
+"{"
+"<3D82AB4D-62DA-11CF-AB39-0020AF71E433>"
+"ColorRGBA faceColor;"
+"FLOAT power;"
+"ColorRGB specularColor;"
+"ColorRGB emissiveColor;"
+"[...]"
+"}"
+"template MeshFace"
+"{"
+"<3D82AB5F-62DA-11CF-AB39-0020AF71E433>"
+"DWORD nFaceVertexIndices;"
+"array DWORD faceVertexIndices[nFaceVertexIndices];"
+"}"
+"template MeshFaceWraps"
+"{"
+"<ED1EC5C0-C0A8-11D0-941C-0080C80CFA7B>"
+"DWORD nFaceWrapValues;"
+"array Boolean2d faceWrapValues[nFaceWrapValues];"
+"}"
+"template MeshTextureCoords"
+"{"
+"<F6F23F40-7686-11CF-8F52-0040333594A3>"
+"DWORD nTextureCoords;"
+"array Coords2d textureCoords[nTextureCoords];"
+"}"
+"template MeshMaterialList"
+"{"
+"<F6F23F42-7686-11CF-8F52-0040333594A3>"
+"DWORD nMaterials;"
+"DWORD nFaceIndexes;"
+"array DWORD faceIndexes[nFaceIndexes];"
+"[Material]"
+"}"
+"template MeshNormals"
+"{"
+"<F6F23F43-7686-11CF-8F52-0040333594A3>"
+"DWORD nNormals;"
+"array Vector normals[nNormals];"
+"DWORD nFaceNormals;"
+"array MeshFace faceNormals[nFaceNormals];"
+"}"
+"template MeshVertexColors"
+"{"
+"<1630B821-7842-11CF-8F52-0040333594A3>"
+"DWORD nVertexColors;"
+"array IndexedColor vertexColors[nVertexColors];"
+"}"
+"template Mesh"
+"{"
+"<3D82AB44-62DA-11CF-AB39-0020AF71E433>"
+"DWORD nVertices;"
+"array Vector vertices[nVertices];"
+"DWORD nFaces;"
+"array MeshFace faces[nFaces];"
+"[...]"
+"}"
+"template FrameTransformMatrix"
+"{"
+"<F6F23F41-7686-11CF-8F52-0040333594A3>"
+"Matrix4x4 frameMatrix;"
+"}"
+"template Frame"
+"{"
+"<3D82AB46-62DA-11CF-AB39-0020AF71E433>"
+"[...]"
+"}"
+"template FloatKeys"
+"{"
+"<10DD46A9-775B-11CF-8F52-0040333594A3>"
+"DWORD nValues;"
+"array FLOAT values[nValues];"
+"}"
+"template TimedFloatKeys"
+"{"
+"<F406B180-7B3B-11CF-8F52-0040333594A3>"
+"DWORD time;"
+"FloatKeys tfkeys;"
+"}"
+"template AnimationKey"
+"{"
+"<10DD46A8-775B-11CF-8F52-0040333594A3>"
+"DWORD keyType;"
+"DWORD nKeys;"
+"array TimedFloatKeys keys[nKeys];"
+"}"
+"template AnimationOptions"
+"{"
+"<E2BF56C0-840F-11CF-8F52-0040333594A3>"
+"DWORD openclosed;"
+"DWORD positionquality;"
+"}"
+"template Animation"
+"{"
+"<3D82AB4F-62DA-11CF-AB39-0020AF71E433>"
+"[...]"
+"}"
+"template AnimationSet"
+"{"
+"<3D82AB50-62DA-11CF-AB39-0020AF71E433>"
+"[Animation]"
+"}"
+"template InlineData"
+"{"
+"<3A23EEA0-94B1-11D0-AB39-0020AF71E433>"
+"[BINARY]"
+"}"
+"template Url"
+"{"
+"<3A23EEA1-94B1-11D0-AB39-0020AF71E433>"
+"DWORD nUrls;"
+"array STRING urls[nUrls];"
+"}"
+"template ProgressiveMesh"
+"{"
+"<8A63C360-997D-11D0-941C-0080C80CFA7B>"
+"[Url,InlineData]"
+"}"
+"template Guid"
+"{"
+"<A42790E0-7810-11CF-8F52-0040333594A3>"
+"DWORD data1;"
+"WORD data2;"
+"WORD data3;"
+"array UCHAR data4[8];"
+"}"
+"template StringProperty"
+"{"
+"<7F0F21E0-BFE1-11D1-82C0-00A0C9697271>"
+"STRING key;"
+"STRING value;"
+"}"
+"template PropertyBag"
+"{"
+"<7F0F21E1-BFE1-11D1-82C0-00A0C9697271>"
+"[StringProperty]"
+"}"
+"template ExternalVisual"
+"{"
+"<98116AA0-BDBA-11D1-82C0-00A0C9697271>"
+"Guid guidExternalVisual;"
+"[...]"
+"}"
+"template RightHanded"
+"{"
+"<7F5D5EA0-D53A-11D1-82C0-00A0C9697271>"
+"DWORD bRightHanded;"
+"}"
+};
+
+static inline struct d3drm_mesh *impl_from_IDirect3DRMMesh(IDirect3DRMMesh *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_mesh, IDirect3DRMMesh_iface);
+}
+
+static inline struct d3drm_mesh_builder *impl_from_IDirect3DRMMeshBuilder2(IDirect3DRMMeshBuilder2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_mesh_builder, IDirect3DRMMeshBuilder2_iface);
+}
+
+static inline struct d3drm_mesh_builder *impl_from_IDirect3DRMMeshBuilder3(IDirect3DRMMeshBuilder3 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_mesh_builder, IDirect3DRMMeshBuilder3_iface);
+}
+
+static void clean_mesh_builder_data(struct d3drm_mesh_builder *mesh_builder)
+{
+    DWORD i;
+
+    HeapFree(GetProcessHeap(), 0, mesh_builder->name);
+    mesh_builder->name = NULL;
+    HeapFree(GetProcessHeap(), 0, mesh_builder->pVertices);
+    mesh_builder->pVertices = NULL;
+    mesh_builder->nb_vertices = 0;
+    HeapFree(GetProcessHeap(), 0, mesh_builder->pNormals);
+    mesh_builder->pNormals = NULL;
+    mesh_builder->nb_normals = 0;
+    HeapFree(GetProcessHeap(), 0, mesh_builder->pFaceData);
+    mesh_builder->pFaceData = NULL;
+    mesh_builder->face_data_size = 0;
+    mesh_builder->nb_faces = 0;
+    HeapFree(GetProcessHeap(), 0, mesh_builder->pCoords2d);
+    mesh_builder->pCoords2d = NULL;
+    mesh_builder->nb_coords2d = 0;
+    for (i = 0; i < mesh_builder->nb_materials; i++)
+    {
+        if (mesh_builder->materials[i].material)
+            IDirect3DRMMaterial2_Release(mesh_builder->materials[i].material);
+        if (mesh_builder->materials[i].texture)
+            IDirect3DRMTexture3_Release(mesh_builder->materials[i].texture);
+    }
+    mesh_builder->nb_materials = 0;
+    HeapFree(GetProcessHeap(), 0, mesh_builder->materials);
+    HeapFree(GetProcessHeap(), 0, mesh_builder->material_indices);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_QueryInterface(IDirect3DRMMeshBuilder2 *iface, REFIID riid, void **out)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMMeshBuilder2)
+            || IsEqualGUID(riid, &IID_IDirect3DRMMeshBuilder)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *out = &mesh_builder->IDirect3DRMMeshBuilder2_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRMMeshBuilder3))
+    {
+        *out = &mesh_builder->IDirect3DRMMeshBuilder3_iface;
+    }
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI d3drm_mesh_builder2_AddRef(IDirect3DRMMeshBuilder2 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+    ULONG refcount = InterlockedIncrement(&mesh_builder->ref);
+
+    TRACE("%p increasing refcount to %u.\n", mesh_builder, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_mesh_builder2_Release(IDirect3DRMMeshBuilder2 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+    ULONG refcount = InterlockedDecrement(&mesh_builder->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", mesh_builder, refcount);
+
+    if (!refcount)
+    {
+        clean_mesh_builder_data(mesh_builder);
+        if (mesh_builder->material)
+            IDirect3DRMMaterial2_Release(mesh_builder->material);
+        if (mesh_builder->texture)
+            IDirect3DRMTexture3_Release(mesh_builder->texture);
+        HeapFree(GetProcessHeap(), 0, mesh_builder);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_Clone(IDirect3DRMMeshBuilder2 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_AddDestroyCallback(IDirect3DRMMeshBuilder2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_DeleteDestroyCallback(IDirect3DRMMeshBuilder2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetAppData(IDirect3DRMMeshBuilder2 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_mesh_builder2_GetAppData(IDirect3DRMMeshBuilder2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetName(IDirect3DRMMeshBuilder2 *iface, const char *name)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_a(name));
+
+    return IDirect3DRMMeshBuilder3_SetName(&mesh_builder->IDirect3DRMMeshBuilder3_iface, name);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GetName(IDirect3DRMMeshBuilder2 *iface, DWORD *size, char *name)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    return IDirect3DRMMeshBuilder3_GetName(&mesh_builder->IDirect3DRMMeshBuilder3_iface, size, name);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GetClassName(IDirect3DRMMeshBuilder2 *iface, DWORD *size, char *name)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    return IDirect3DRMMeshBuilder3_GetClassName(&mesh_builder->IDirect3DRMMeshBuilder3_iface, size, name);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_Load(IDirect3DRMMeshBuilder2 *iface, void *filename,
+        void *name, D3DRMLOADOPTIONS flags, D3DRMLOADTEXTURECALLBACK cb, void *ctx)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, filename %p, name %p, flags %#x, cb %p, ctx %p.\n",
+            iface, filename, name, flags, cb, ctx);
+
+    if (cb)
+        FIXME("Texture callback is not yet supported\n");
+
+    return IDirect3DRMMeshBuilder3_Load(&mesh_builder->IDirect3DRMMeshBuilder3_iface,
+            filename, name, flags, NULL, ctx);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_Save(IDirect3DRMMeshBuilder2 *iface,
+        const char *filename, D3DRMXOFFORMAT format, D3DRMSAVEOPTIONS flags)
+{
+    FIXME("iface %p, filename %s, format %#x, flags %#x stub!\n",
+            iface, debugstr_a(filename), format, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_Scale(IDirect3DRMMeshBuilder2 *iface,
+        D3DVALUE sx, D3DVALUE sy, D3DVALUE sz)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, sx %.8e, sy %.8e, sz %.8e.\n", iface, sx, sy, sz);
+
+    return IDirect3DRMMeshBuilder3_Scale(&mesh_builder->IDirect3DRMMeshBuilder3_iface, sx, sy, sz);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_Translate(IDirect3DRMMeshBuilder2 *iface,
+        D3DVALUE tx, D3DVALUE ty, D3DVALUE tz)
+{
+    FIXME("iface %p, tx %.8e, ty %.8e, tz %.8e stub!\n", iface, tx, ty, tz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetColorSource(IDirect3DRMMeshBuilder2 *iface, D3DRMCOLORSOURCE source)
+{
+    FIXME("iface %p, source %#x stub!\n", iface, source);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GetBox(IDirect3DRMMeshBuilder2 *iface, D3DRMBOX *box)
+{
+    FIXME("iface %p, box %p stub!\n", iface, box);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GenerateNormals(IDirect3DRMMeshBuilder2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMCOLORSOURCE WINAPI d3drm_mesh_builder2_GetColorSource(IDirect3DRMMeshBuilder2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_AddMesh(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMMesh *mesh)
+{
+    FIXME("iface %p, mesh %p stub!\n", iface, mesh);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_AddMeshBuilder(IDirect3DRMMeshBuilder2 *iface,
+        IDirect3DRMMeshBuilder *mesh_builder)
+{
+    FIXME("iface %p, mesh_builder %p stub!\n", iface, mesh_builder);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_AddFrame(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMFrame *frame)
+{
+    FIXME("iface %p, frame %p stub!\n", iface, frame);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_AddFace(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMFace *face)
+{
+    FIXME("iface %p, face %p stub!\n", iface, face);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_AddFaces(IDirect3DRMMeshBuilder2 *iface,
+        DWORD vertex_count, D3DVECTOR *vertices, DWORD normal_count, D3DVECTOR *normals,
+        DWORD *face_data, IDirect3DRMFaceArray **array)
+{
+    FIXME("iface %p, vertex_count %u, vertices %p, normal_count %u, normals %p, face_data %p, array %p stub!\n",
+            iface, vertex_count, vertices, normal_count, normals, face_data, array);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_ReserveSpace(IDirect3DRMMeshBuilder2 *iface,
+        DWORD vertex_count, DWORD normal_count, DWORD face_count)
+{
+    FIXME("iface %p, vertex_count %u, normal_count %u, face_count %u stub!\n",
+            iface, vertex_count, normal_count, face_count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetColorRGB(IDirect3DRMMeshBuilder2 *iface,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, red %.8e, green %.8e, blue %.8e.\n", iface, red, green, blue);
+
+    return IDirect3DRMMeshBuilder3_SetColorRGB(&mesh_builder->IDirect3DRMMeshBuilder3_iface, red, green, blue);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetColor(IDirect3DRMMeshBuilder2 *iface, D3DCOLOR color)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, color 0x%08x.\n", iface, color);
+
+    return IDirect3DRMMeshBuilder3_SetColor(&mesh_builder->IDirect3DRMMeshBuilder3_iface, color);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetTexture(IDirect3DRMMeshBuilder2 *iface,
+        IDirect3DRMTexture *texture)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+    IDirect3DRMTexture3 *texture3 = NULL;
+    HRESULT hr = D3DRM_OK;
+
+    TRACE("iface %p, texture %p.\n", iface, texture);
+
+    if (texture)
+        hr = IDirect3DRMTexture_QueryInterface(texture, &IID_IDirect3DRMTexture3, (void **)&texture3);
+    if (SUCCEEDED(hr))
+        hr = IDirect3DRMMeshBuilder3_SetTexture(&mesh_builder->IDirect3DRMMeshBuilder3_iface, texture3);
+    if (texture3)
+        IDirect3DRMTexture3_Release(texture3);
+
+    return hr;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetMaterial(IDirect3DRMMeshBuilder2 *iface,
+        IDirect3DRMMaterial *material)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, material %p.\n", iface, material);
+
+    return IDirect3DRMMeshBuilder3_SetMaterial(&mesh_builder->IDirect3DRMMeshBuilder3_iface,
+            (IDirect3DRMMaterial2 *)material);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetTextureTopology(IDirect3DRMMeshBuilder2 *iface,
+        BOOL wrap_u, BOOL wrap_v)
+{
+    FIXME("iface %p, wrap_u %#x, wrap_v %#x stub!\n", iface, wrap_u, wrap_v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetQuality(IDirect3DRMMeshBuilder2 *iface,
+        D3DRMRENDERQUALITY quality)
+{
+    FIXME("iface %p, quality %#x stub!\n", iface, quality);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetPerspective(IDirect3DRMMeshBuilder2 *iface, BOOL enable)
+{
+    FIXME("iface %p, enable %#x stub!\n", iface, enable);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetVertex(IDirect3DRMMeshBuilder2 *iface,
+        DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, index %u, x %.8e, y %.8e, z %.8e stub!\n", iface, index, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetNormal(IDirect3DRMMeshBuilder2 *iface,
+        DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, index %u, x %.8e, y %.8e, z %.8e stub!\n", iface, index, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetTextureCoordinates(IDirect3DRMMeshBuilder2 *iface,
+        DWORD index, D3DVALUE u, D3DVALUE v)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, index %u, u %.8e, v %.8e.\n", iface, index, u, v);
+
+    return IDirect3DRMMeshBuilder3_SetTextureCoordinates(&mesh_builder->IDirect3DRMMeshBuilder3_iface,
+            index, u, v);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetVertexColor(IDirect3DRMMeshBuilder2 *iface,
+        DWORD index, D3DCOLOR color)
+{
+    FIXME("iface %p, index %u, color 0x%08x stub!\n", iface, index, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_SetVertexColorRGB(IDirect3DRMMeshBuilder2 *iface,
+        DWORD index, D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    FIXME("iface %p, index %u, red %.8e, green %.8e, blue %.8e stub!\n",
+            iface, index, red, green, blue);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GetFaces(IDirect3DRMMeshBuilder2 *iface,
+        IDirect3DRMFaceArray **array)
+{
+    FIXME("iface %p, array %p stub!\n", iface, array);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GetVertices(IDirect3DRMMeshBuilder2 *iface,
+        DWORD *vertex_count, D3DVECTOR *vertices, DWORD *normal_count, D3DVECTOR *normals,
+        DWORD *face_data_size, DWORD *face_data)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, vertex_count %p, vertices %p, normal_count %p, normals %p, face_data_size %p, face_data %p.\n",
+            iface, vertex_count, vertices, normal_count, normals, face_data_size, face_data);
+
+    if (vertices && (!vertex_count || (*vertex_count < mesh_builder->nb_vertices)))
+        return D3DRMERR_BADVALUE;
+    if (vertex_count)
+        *vertex_count = mesh_builder->nb_vertices;
+    if (vertices && mesh_builder->nb_vertices)
+        memcpy(vertices, mesh_builder->pVertices, mesh_builder->nb_vertices * sizeof(*vertices));
+
+    if (normals && (!normal_count || (*normal_count < mesh_builder->nb_normals)))
+        return D3DRMERR_BADVALUE;
+    if (normal_count)
+        *normal_count = mesh_builder->nb_normals;
+    if (normals && mesh_builder->nb_normals)
+        memcpy(normals, mesh_builder->pNormals, mesh_builder->nb_normals * sizeof(*normals));
+
+    if (face_data && (!face_data_size || (*face_data_size < mesh_builder->face_data_size)))
+        return D3DRMERR_BADVALUE;
+    if (face_data_size)
+        *face_data_size = mesh_builder->face_data_size;
+    if (face_data && mesh_builder->face_data_size)
+        memcpy(face_data, mesh_builder->pFaceData, mesh_builder->face_data_size * sizeof(*face_data));
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GetTextureCoordinates(IDirect3DRMMeshBuilder2 *iface,
+        DWORD index, D3DVALUE *u, D3DVALUE *v)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, index %u, u %p, v %p.\n", iface, index, u, v);
+
+    return IDirect3DRMMeshBuilder3_GetTextureCoordinates(&mesh_builder->IDirect3DRMMeshBuilder3_iface,
+            index, u, v);
+}
+
+static int WINAPI d3drm_mesh_builder2_AddVertex(IDirect3DRMMeshBuilder2 *iface,
+        D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, x %.8e, y %.8e, z %.8e stub!\n", iface, x, y, z);
+
+    return 0;
+}
+
+static int WINAPI d3drm_mesh_builder2_AddNormal(IDirect3DRMMeshBuilder2 *iface,
+        D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, x %.8e, y %.8e, z %.8e stub!\n", iface, x, y, z);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_CreateFace(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMFace **face)
+{
+    TRACE("iface %p, face %p.\n", iface, face);
+
+    return Direct3DRMFace_create(&IID_IDirect3DRMFace, (IUnknown **)face);
+}
+
+static D3DRMRENDERQUALITY WINAPI d3drm_mesh_builder2_GetQuality(IDirect3DRMMeshBuilder2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static BOOL WINAPI d3drm_mesh_builder2_GetPerspective(IDirect3DRMMeshBuilder2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return FALSE;
+}
+
+static int WINAPI d3drm_mesh_builder2_GetFaceCount(IDirect3DRMMeshBuilder2 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return mesh_builder->nb_faces;
+}
+
+static int WINAPI d3drm_mesh_builder2_GetVertexCount(IDirect3DRMMeshBuilder2 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return mesh_builder->nb_vertices;
+}
+
+static D3DCOLOR WINAPI d3drm_mesh_builder2_GetVertexColor(IDirect3DRMMeshBuilder2 *iface, DWORD index)
+{
+    FIXME("iface %p, index %u stub!\n", iface, index);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_CreateMesh(IDirect3DRMMeshBuilder2 *iface, IDirect3DRMMesh **mesh)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder2(iface);
+
+    TRACE("iface %p, mesh %p.\n", iface, mesh);
+
+    return IDirect3DRMMeshBuilder3_CreateMesh(&mesh_builder->IDirect3DRMMeshBuilder3_iface, mesh);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GenerateNormals2(IDirect3DRMMeshBuilder2 *iface,
+        D3DVALUE crease, DWORD flags)
+{
+    FIXME("iface %p, crease %.8e, flags %#x stub!\n", iface, crease, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder2_GetFace(IDirect3DRMMeshBuilder2 *iface,
+        DWORD index, IDirect3DRMFace **face)
+{
+    FIXME("iface %p, index %u, face %p stub!\n", iface, index, face);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMMeshBuilder2Vtbl d3drm_mesh_builder2_vtbl =
+{
+    d3drm_mesh_builder2_QueryInterface,
+    d3drm_mesh_builder2_AddRef,
+    d3drm_mesh_builder2_Release,
+    d3drm_mesh_builder2_Clone,
+    d3drm_mesh_builder2_AddDestroyCallback,
+    d3drm_mesh_builder2_DeleteDestroyCallback,
+    d3drm_mesh_builder2_SetAppData,
+    d3drm_mesh_builder2_GetAppData,
+    d3drm_mesh_builder2_SetName,
+    d3drm_mesh_builder2_GetName,
+    d3drm_mesh_builder2_GetClassName,
+    d3drm_mesh_builder2_Load,
+    d3drm_mesh_builder2_Save,
+    d3drm_mesh_builder2_Scale,
+    d3drm_mesh_builder2_Translate,
+    d3drm_mesh_builder2_SetColorSource,
+    d3drm_mesh_builder2_GetBox,
+    d3drm_mesh_builder2_GenerateNormals,
+    d3drm_mesh_builder2_GetColorSource,
+    d3drm_mesh_builder2_AddMesh,
+    d3drm_mesh_builder2_AddMeshBuilder,
+    d3drm_mesh_builder2_AddFrame,
+    d3drm_mesh_builder2_AddFace,
+    d3drm_mesh_builder2_AddFaces,
+    d3drm_mesh_builder2_ReserveSpace,
+    d3drm_mesh_builder2_SetColorRGB,
+    d3drm_mesh_builder2_SetColor,
+    d3drm_mesh_builder2_SetTexture,
+    d3drm_mesh_builder2_SetMaterial,
+    d3drm_mesh_builder2_SetTextureTopology,
+    d3drm_mesh_builder2_SetQuality,
+    d3drm_mesh_builder2_SetPerspective,
+    d3drm_mesh_builder2_SetVertex,
+    d3drm_mesh_builder2_SetNormal,
+    d3drm_mesh_builder2_SetTextureCoordinates,
+    d3drm_mesh_builder2_SetVertexColor,
+    d3drm_mesh_builder2_SetVertexColorRGB,
+    d3drm_mesh_builder2_GetFaces,
+    d3drm_mesh_builder2_GetVertices,
+    d3drm_mesh_builder2_GetTextureCoordinates,
+    d3drm_mesh_builder2_AddVertex,
+    d3drm_mesh_builder2_AddNormal,
+    d3drm_mesh_builder2_CreateFace,
+    d3drm_mesh_builder2_GetQuality,
+    d3drm_mesh_builder2_GetPerspective,
+    d3drm_mesh_builder2_GetFaceCount,
+    d3drm_mesh_builder2_GetVertexCount,
+    d3drm_mesh_builder2_GetVertexColor,
+    d3drm_mesh_builder2_CreateMesh,
+    d3drm_mesh_builder2_GenerateNormals2,
+    d3drm_mesh_builder2_GetFace,
+};
+
+static HRESULT WINAPI d3drm_mesh_builder3_QueryInterface(IDirect3DRMMeshBuilder3 *iface, REFIID riid, void **out)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    return d3drm_mesh_builder2_QueryInterface(&mesh_builder->IDirect3DRMMeshBuilder2_iface, riid, out);
+}
+
+static ULONG WINAPI d3drm_mesh_builder3_AddRef(IDirect3DRMMeshBuilder3 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return d3drm_mesh_builder2_AddRef(&mesh_builder->IDirect3DRMMeshBuilder2_iface);
+}
+
+static ULONG WINAPI d3drm_mesh_builder3_Release(IDirect3DRMMeshBuilder3 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return d3drm_mesh_builder2_Release(&mesh_builder->IDirect3DRMMeshBuilder2_iface);
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_Clone(IDirect3DRMMeshBuilder3 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_AddDestroyCallback(IDirect3DRMMeshBuilder3 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_DeleteDestroyCallback(IDirect3DRMMeshBuilder3 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetAppData(IDirect3DRMMeshBuilder3 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_mesh_builder3_GetAppData(IDirect3DRMMeshBuilder3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetName(IDirect3DRMMeshBuilder3 *iface, const char *name)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+    char *string = NULL;
+
+    TRACE("iface %p, name %s.\n", iface, debugstr_a(name));
+
+    if (name)
+    {
+        string = HeapAlloc(GetProcessHeap(), 0, strlen(name) + 1);
+        if (!string) return E_OUTOFMEMORY;
+        strcpy(string, name);
+    }
+    HeapFree(GetProcessHeap(), 0, mesh_builder->name);
+    mesh_builder->name = string;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetName(IDirect3DRMMeshBuilder3 *iface,
+        DWORD *size, char *name)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size)
+        return E_POINTER;
+
+    if (!mesh_builder->name)
+    {
+        *size = 0;
+        return D3DRM_OK;
+    }
+
+    if (*size < (strlen(mesh_builder->name) + 1))
+        return E_INVALIDARG;
+
+    strcpy(name, mesh_builder->name);
+    *size = strlen(mesh_builder->name) + 1;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetClassName(IDirect3DRMMeshBuilder3 *iface,
+        DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Builder") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Builder");
+    *size = sizeof("Builder");
+
+    return D3DRM_OK;
+}
+
+HRESULT load_mesh_data(IDirect3DRMMeshBuilder3 *iface, IDirectXFileData *pData,
+        D3DRMLOADTEXTURECALLBACK load_texture_proc, void *arg)
+{
+    struct d3drm_mesh_builder *This = impl_from_IDirect3DRMMeshBuilder3(iface);
+    IDirectXFileData *pData2 = NULL;
+    const GUID* guid;
+    DWORD size;
+    BYTE *ptr;
+    HRESULT hr;
+    HRESULT ret = D3DRMERR_BADOBJECT;
+    DWORD* faces_vertex_idx_data = NULL;
+    DWORD* faces_vertex_idx_ptr;
+    DWORD faces_vertex_idx_size;
+    DWORD* faces_normal_idx_data = NULL;
+    DWORD* faces_normal_idx_ptr = NULL;
+    DWORD* faces_data_ptr;
+    DWORD faces_data_size = 0;
+    DWORD i;
+
+    TRACE("(%p)->(%p)\n", This, pData);
+
+    hr = IDirectXFileData_GetName(pData, NULL, &size);
+    if (hr != DXFILE_OK)
+        return hr;
+    if (size)
+    {
+        This->name = HeapAlloc(GetProcessHeap(), 0, size);
+        if (!This->name)
+            return E_OUTOFMEMORY;
+
+        hr = IDirectXFileData_GetName(pData, This->name, &size);
+        if (hr != DXFILE_OK)
+            return hr;
+    }
+
+    TRACE("Mesh name is '%s'\n", This->name ? This->name : "");
+
+    This->nb_normals = 0;
+
+    hr = IDirectXFileData_GetData(pData, NULL, &size, (void**)&ptr);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    This->nb_vertices = *(DWORD*)ptr;
+    This->nb_faces = *(DWORD*)(ptr + sizeof(DWORD) + This->nb_vertices * sizeof(D3DVECTOR));
+    faces_vertex_idx_size = size - sizeof(DWORD) - This->nb_vertices * sizeof(D3DVECTOR) - sizeof(DWORD);
+    faces_vertex_idx_ptr = (DWORD*)(ptr + sizeof(DWORD) + This->nb_vertices * sizeof(D3DVECTOR) + sizeof(DWORD));
+
+    TRACE("Mesh: nb_vertices = %d, nb_faces = %d, faces_vertex_idx_size = %d\n", This->nb_vertices, This->nb_faces, faces_vertex_idx_size);
+
+    This->pVertices = HeapAlloc(GetProcessHeap(), 0, This->nb_vertices * sizeof(D3DVECTOR));
+    memcpy(This->pVertices, ptr + sizeof(DWORD), This->nb_vertices * sizeof(D3DVECTOR));
+
+    faces_vertex_idx_ptr = faces_vertex_idx_data = HeapAlloc(GetProcessHeap(), 0, faces_vertex_idx_size);
+    memcpy(faces_vertex_idx_data, ptr + sizeof(DWORD) + This->nb_vertices * sizeof(D3DVECTOR) + sizeof(DWORD), faces_vertex_idx_size);
+
+    /* Each vertex index will have its normal index counterpart so just allocate twice the size */
+    This->pFaceData = HeapAlloc(GetProcessHeap(), 0, faces_vertex_idx_size * 2);
+    faces_data_ptr = (DWORD*)This->pFaceData;
+
+    while (1)
+    {
+        IDirectXFileObject *object;
+
+        hr =  IDirectXFileData_GetNextObject(pData, &object);
+        if (hr == DXFILEERR_NOMOREOBJECTS)
+        {
+            TRACE("No more object\n");
+            break;
+        }
+        if (hr != DXFILE_OK)
+           goto end;
+
+        hr = IDirectXFileObject_QueryInterface(object, &IID_IDirectXFileData, (void**)&pData2);
+        IDirectXFileObject_Release(object);
+        if (hr != DXFILE_OK)
+            goto end;
+
+        hr = IDirectXFileData_GetType(pData2, &guid);
+        if (hr != DXFILE_OK)
+            goto end;
+
+        TRACE("Found object type whose GUID = %s\n", debugstr_guid(guid));
+
+        if (IsEqualGUID(guid, &TID_D3DRMMeshNormals))
+        {
+            DWORD nb_faces_normals;
+            DWORD faces_normal_idx_size;
+
+            hr = IDirectXFileData_GetData(pData2, NULL, &size, (void**)&ptr);
+            if (hr != DXFILE_OK)
+                goto end;
+
+            This->nb_normals = *(DWORD*)ptr;
+            nb_faces_normals = *(DWORD*)(ptr + sizeof(DWORD) + This->nb_normals * sizeof(D3DVECTOR));
+
+            TRACE("MeshNormals: nb_normals = %d, nb_faces_normals = %d\n", This->nb_normals, nb_faces_normals);
+            if (nb_faces_normals != This->nb_faces)
+                WARN("nb_face_normals (%d) != nb_faces (%d)\n", nb_faces_normals, This->nb_normals);
+
+            This->pNormals = HeapAlloc(GetProcessHeap(), 0, This->nb_normals * sizeof(D3DVECTOR));
+            memcpy(This->pNormals, ptr + sizeof(DWORD), This->nb_normals * sizeof(D3DVECTOR));
+
+            faces_normal_idx_size = size - (2 * sizeof(DWORD) + This->nb_normals * sizeof(D3DVECTOR));
+            faces_normal_idx_ptr = faces_normal_idx_data = HeapAlloc(GetProcessHeap(), 0, faces_normal_idx_size);
+            memcpy(faces_normal_idx_data, ptr + sizeof(DWORD) + This->nb_normals * sizeof(D3DVECTOR) + sizeof(DWORD), faces_normal_idx_size);
+        }
+        else if (IsEqualGUID(guid, &TID_D3DRMMeshTextureCoords))
+        {
+            hr = IDirectXFileData_GetData(pData2, NULL, &size, (void**)&ptr);
+            if (hr != DXFILE_OK)
+                goto end;
+
+            This->nb_coords2d = *(DWORD*)ptr;
+
+            TRACE("MeshTextureCoords: nb_coords2d = %d\n", This->nb_coords2d);
+
+            This->pCoords2d = HeapAlloc(GetProcessHeap(), 0, This->nb_coords2d * sizeof(*This->pCoords2d));
+            memcpy(This->pCoords2d, ptr + sizeof(DWORD), This->nb_coords2d * sizeof(*This->pCoords2d));
+
+        }
+        else if (IsEqualGUID(guid, &TID_D3DRMMeshMaterialList))
+        {
+            DWORD nb_materials;
+            DWORD nb_face_indices;
+            DWORD data_size;
+            IDirectXFileObject *child;
+            DWORD i = 0;
+            float* values;
+
+            TRACE("Process MeshMaterialList\n");
+
+            hr = IDirectXFileData_GetData(pData2, NULL, &size, (void**)&ptr);
+            if (hr != DXFILE_OK)
+                goto end;
+
+            nb_materials = *(DWORD*)ptr;
+            nb_face_indices = *(DWORD*)(ptr + sizeof(DWORD));
+            data_size = 2 * sizeof(DWORD) + nb_face_indices * sizeof(DWORD);
+
+            TRACE("nMaterials = %u, nFaceIndexes = %u\n", nb_materials, nb_face_indices);
+
+            if (size != data_size)
+                WARN("Returned size %u does not match expected one %u\n", size, data_size);
+
+            This->material_indices = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->material_indices) * nb_face_indices);
+            if (!This->material_indices)
+                goto end;
+            memcpy(This->material_indices, ptr + 2 * sizeof(DWORD), sizeof(*This->material_indices) * nb_face_indices),
+
+            This->materials = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->materials) * nb_materials);
+            if (!This->materials)
+            {
+                HeapFree(GetProcessHeap(), 0, This->material_indices);
+                goto end;
+            }
+            This->nb_materials = nb_materials;
+
+            while (SUCCEEDED(hr = IDirectXFileData_GetNextObject(pData2, &child)) && (i < nb_materials))
+            {
+                IDirectXFileData *data;
+                IDirectXFileDataReference *reference;
+                IDirectXFileObject *material_child;
+
+                hr = IDirectXFileObject_QueryInterface(child, &IID_IDirectXFileData, (void **)&data);
+                if (FAILED(hr))
+                {
+                    hr = IDirectXFileObject_QueryInterface(child, &IID_IDirectXFileDataReference, (void **)&reference);
+                    IDirectXFileObject_Release(child);
+                    if (FAILED(hr))
+                        goto end;
+
+                    hr = IDirectXFileDataReference_Resolve(reference, &data);
+                    IDirectXFileDataReference_Release(reference);
+                    if (FAILED(hr))
+                        goto end;
+                }
+                else
+                {
+                    IDirectXFileObject_Release(child);
+                }
+
+                hr = Direct3DRMMaterial_create(&This->materials[i].material);
+                if (FAILED(hr))
+                {
+                    IDirectXFileData_Release(data);
+                    goto end;
+                }
+
+                hr = IDirectXFileData_GetData(data, NULL, &size, (void**)&ptr);
+                if (hr != DXFILE_OK)
+                {
+                    IDirectXFileData_Release(data);
+                    goto end;
+                }
+
+                if (size != 44)
+                    WARN("Material size %u does not match expected one %u\n", size, 44);
+
+                values = (float*)ptr;
+
+                This->materials[i].color = RGBA_MAKE((BYTE)(values[0] * 255.0f), (BYTE)(values[1] * 255.0f),
+                        (BYTE)(values[2] * 255.0f), (BYTE)(values[3] * 255.0f));
+
+                IDirect3DRMMaterial2_SetAmbient(This->materials[i].material, values[0], values [1], values[2]); /* Alpha ignored */
+                IDirect3DRMMaterial2_SetPower(This->materials[i].material, values[4]);
+                IDirect3DRMMaterial2_SetSpecular(This->materials[i].material, values[5], values[6], values[7]);
+                IDirect3DRMMaterial2_SetEmissive(This->materials[i].material, values[8], values[9], values[10]);
+
+                This->materials[i].texture = NULL;
+
+                hr = IDirectXFileData_GetNextObject(data, &material_child);
+                if (hr == S_OK)
+                {
+                    IDirectXFileData *data;
+                    char **filename;
+
+                    hr = IDirectXFileObject_QueryInterface(material_child, &IID_IDirectXFileData, (void **)&data);
+                    if (FAILED(hr))
+                    {
+                        IDirectXFileDataReference *reference;
+
+                        hr = IDirectXFileObject_QueryInterface(material_child, &IID_IDirectXFileDataReference, (void **)&reference);
+                        if (FAILED(hr))
+                            goto end;
+
+                        hr = IDirectXFileDataReference_Resolve(reference, &data);
+                        IDirectXFileDataReference_Release(reference);
+                        if (FAILED(hr))
+                            goto end;
+                    }
+
+                    hr = IDirectXFileData_GetType(data, &guid);
+                    if (hr != DXFILE_OK)
+                        goto end;
+                    if (!IsEqualGUID(guid, &TID_D3DRMTextureFilename))
+                    {
+                         WARN("Not a texture filename\n");
+                         goto end;
+                    }
+
+                    size = 4;
+                    hr = IDirectXFileData_GetData(data, NULL, &size, (void**)&filename);
+                    if (SUCCEEDED(hr))
+                    {
+                        if (load_texture_proc)
+                        {
+                            IDirect3DRMTexture *texture;
+
+                            hr = load_texture_proc(*filename, arg, &texture);
+                            if (SUCCEEDED(hr))
+                            {
+                                hr = IDirect3DTexture_QueryInterface(texture, &IID_IDirect3DRMTexture3, (void**)&This->materials[i].texture);
+                                IDirect3DTexture_Release(texture);
+                            }
+                        }
+                        else
+                        {
+                            HANDLE file;
+
+                            /* If the texture file is not found, no texture is associated with the material */
+                            file = CreateFileA(*filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+                            if (file != INVALID_HANDLE_VALUE)
+                            {
+                                CloseHandle(file);
+
+                                hr = Direct3DRMTexture_create(&IID_IDirect3DRMTexture3, (IUnknown**)&This->materials[i].texture);
+                                if (FAILED(hr))
+                                {
+                                    IDirectXFileData_Release(data);
+                                    goto end;
+                                }
+                            }
+                        }
+                    }
+                }
+                else if (hr != DXFILEERR_NOMOREOBJECTS)
+                {
+                    goto end;
+                }
+                hr = S_OK;
+
+                IDirectXFileData_Release(data);
+                i++;
+            }
+            if (hr == S_OK)
+            {
+                IDirectXFileObject_Release(child);
+                WARN("Found more sub-objects than expected\n");
+            }
+            else if (hr != DXFILEERR_NOMOREOBJECTS)
+            {
+                goto end;
+            }
+            hr = S_OK;
+        }
+        else
+        {
+            FIXME("Unknown GUID %s, ignoring...\n", debugstr_guid(guid));
+        }
+
+        IDirectXFileData_Release(pData2);
+        pData2 = NULL;
+    }
+
+    if (!This->nb_normals)
+    {
+        /* Allocate normals, one per vertex */
+        This->pNormals = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->nb_vertices * sizeof(D3DVECTOR));
+        if (!This->pNormals)
+            goto end;
+    }
+
+    for (i = 0; i < This->nb_faces; i++)
+    {
+        DWORD j;
+        DWORD nb_face_indexes;
+        D3DVECTOR face_normal;
+
+        if (faces_vertex_idx_size < sizeof(DWORD))
+            WARN("Not enough data to read number of indices of face %d\n", i);
+
+        nb_face_indexes  = *(faces_data_ptr + faces_data_size++) = *(faces_vertex_idx_ptr++);
+        faces_vertex_idx_size--;
+        if (faces_normal_idx_data && (*(faces_normal_idx_ptr++) != nb_face_indexes))
+            WARN("Faces indices number mismatch\n");
+
+        if (faces_vertex_idx_size < (nb_face_indexes * sizeof(DWORD)))
+            WARN("Not enough data to read all indices of face %d\n", i);
+
+        if (!This->nb_normals)
+        {
+            /* Compute face normal */
+            if (nb_face_indexes > 2)
+            {
+                D3DVECTOR a, b;
+
+                D3DRMVectorSubtract(&a, &This->pVertices[faces_vertex_idx_ptr[2]], &This->pVertices[faces_vertex_idx_ptr[1]]);
+                D3DRMVectorSubtract(&b, &This->pVertices[faces_vertex_idx_ptr[0]], &This->pVertices[faces_vertex_idx_ptr[1]]);
+                D3DRMVectorCrossProduct(&face_normal, &a, &b);
+                D3DRMVectorNormalize(&face_normal);
+            }
+            else
+            {
+                face_normal.u1.x = 0.0f;
+                face_normal.u2.y = 0.0f;
+                face_normal.u3.z = 0.0f;
+            }
+        }
+
+        for (j = 0; j < nb_face_indexes; j++)
+        {
+            /* Copy vertex index */
+            *(faces_data_ptr + faces_data_size++) = *faces_vertex_idx_ptr;
+            /* Copy normal index */
+            if (This->nb_normals)
+            {
+                /* Read from x file */
+                *(faces_data_ptr + faces_data_size++) = *(faces_normal_idx_ptr++);
+            }
+            else
+            {
+                DWORD vertex_idx = *faces_vertex_idx_ptr;
+                if (vertex_idx >= This->nb_vertices)
+                {
+                    WARN("Found vertex index %u but only %u vertices available => use index 0\n", vertex_idx, This->nb_vertices);
+                    vertex_idx = 0;
+                }
+                *(faces_data_ptr + faces_data_size++) = vertex_idx;
+                /* Add face normal to vertex normal */
+                D3DRMVectorAdd(&This->pNormals[vertex_idx], &This->pNormals[vertex_idx], &face_normal);
+            }
+            faces_vertex_idx_ptr++;
+        }
+        faces_vertex_idx_size -= nb_face_indexes;
+    }
+
+    /* Last DWORD must be 0 */
+    *(faces_data_ptr + faces_data_size++) = 0;
+
+    /* Set size (in number of DWORD) of all faces data */
+    This->face_data_size = faces_data_size;
+
+    if (!This->nb_normals)
+    {
+        /* Normalize all normals */
+        for (i = 0; i < This->nb_vertices; i++)
+        {
+            D3DRMVectorNormalize(&This->pNormals[i]);
+        }
+        This->nb_normals = This->nb_vertices;
+    }
+
+    /* If there is no texture coordinates, generate default texture coordinates (0.0f, 0.0f) for each vertex */
+    if (!This->pCoords2d)
+    {
+        This->nb_coords2d = This->nb_vertices;
+        This->pCoords2d = HeapAlloc(GetProcessHeap(), 0, This->nb_coords2d * sizeof(*This->pCoords2d));
+        for (i = 0; i < This->nb_coords2d; i++)
+        {
+            This->pCoords2d[i].u = 0.0f;
+            This->pCoords2d[i].v = 0.0f;
+        }
+    }
+
+    TRACE("Mesh data loaded successfully\n");
+
+    ret = D3DRM_OK;
+
+end:
+
+    HeapFree(GetProcessHeap(), 0, faces_normal_idx_data);
+    HeapFree(GetProcessHeap(), 0, faces_vertex_idx_data);
+
+    return ret;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_Load(IDirect3DRMMeshBuilder3 *iface, void *filename,
+        void *name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURE3CALLBACK cb, void *arg)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+    DXFILELOADOPTIONS load_options;
+    IDirectXFile *dxfile = NULL;
+    IDirectXFileEnumObject *enum_object = NULL;
+    IDirectXFileData *data = NULL;
+    const GUID* guid;
+    DWORD size;
+    struct d3drm_file_header *header;
+    HRESULT hr;
+    HRESULT ret = D3DRMERR_BADOBJECT;
+
+    TRACE("iface %p, filename %p, name %p, loadflags %#x, cb %p, arg %p.\n",
+            iface, filename, name, loadflags, cb, arg);
+
+    clean_mesh_builder_data(mesh_builder);
+
+    if (loadflags == D3DRMLOAD_FROMMEMORY)
+    {
+        load_options = DXFILELOAD_FROMMEMORY;
+    }
+    else if (loadflags == D3DRMLOAD_FROMFILE)
+    {
+        load_options = DXFILELOAD_FROMFILE;
+        TRACE("Loading from file %s\n", debugstr_a(filename));
+    }
+    else
+    {
+        FIXME("Load options %d not supported yet\n", loadflags);
+        return E_NOTIMPL;
+    }
+
+    hr = DirectXFileCreate(&dxfile);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    hr = IDirectXFile_RegisterTemplates(dxfile, templates, strlen(templates));
+    if (hr != DXFILE_OK)
+        goto end;
+
+    hr = IDirectXFile_CreateEnumObject(dxfile, filename, load_options, &enum_object);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    hr = IDirectXFileEnumObject_GetNextDataObject(enum_object, &data);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    hr = IDirectXFileData_GetType(data, &guid);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    TRACE("Found object type whose GUID = %s\n", debugstr_guid(guid));
+
+    if (!IsEqualGUID(guid, &TID_DXFILEHeader))
+    {
+        ret = D3DRMERR_BADFILE;
+        goto end;
+    }
+
+    hr = IDirectXFileData_GetData(data, NULL, &size, (void**)&header);
+    if ((hr != DXFILE_OK) || (size != sizeof(*header)))
+        goto end;
+
+    TRACE("Version is %u.%u, flags %#x.\n", header->major, header->minor, header->flags);
+
+    /* Version must be 1.0.x */
+    if ((header->major != 1) || (header->minor != 0))
+    {
+        ret = D3DRMERR_BADFILE;
+        goto end;
+    }
+
+    IDirectXFileData_Release(data);
+    data = NULL;
+
+    hr = IDirectXFileEnumObject_GetNextDataObject(enum_object, &data);
+    if (hr != DXFILE_OK)
+    {
+        ret = D3DRMERR_NOTFOUND;
+        goto end;
+    }
+
+    hr = IDirectXFileData_GetType(data, &guid);
+    if (hr != DXFILE_OK)
+        goto end;
+
+    TRACE("Found object type whose GUID = %s\n", debugstr_guid(guid));
+
+    if (!IsEqualGUID(guid, &TID_D3DRMMesh))
+    {
+        ret = D3DRMERR_NOTFOUND;
+        goto end;
+    }
+
+    /* We don't care about the texture interface version since we rely on QueryInterface */
+    hr = load_mesh_data(iface, data, (D3DRMLOADTEXTURECALLBACK)cb, arg);
+    if (hr == S_OK)
+        ret = D3DRM_OK;
+
+end:
+
+    if (data)
+        IDirectXFileData_Release(data);
+    if (enum_object)
+        IDirectXFileEnumObject_Release(enum_object);
+    if (dxfile)
+        IDirectXFile_Release(dxfile);
+
+    if (ret != D3DRM_OK)
+        clean_mesh_builder_data(mesh_builder);
+
+    return ret;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_Save(IDirect3DRMMeshBuilder3 *iface,
+        const char *filename, D3DRMXOFFORMAT format, D3DRMSAVEOPTIONS flags)
+{
+    FIXME("iface %p, filename %s, format %#x, flags %#x stub!\n",
+            iface, debugstr_a(filename), format, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_Scale(IDirect3DRMMeshBuilder3 *iface,
+        D3DVALUE sx, D3DVALUE sy, D3DVALUE sz)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+    DWORD i;
+
+    TRACE("iface %p, sx %.8e, sy %.8e, sz %.8e.\n", iface, sx, sy, sz);
+
+    for (i = 0; i < mesh_builder->nb_vertices; ++i)
+    {
+        mesh_builder->pVertices[i].u1.x *= sx;
+        mesh_builder->pVertices[i].u2.y *= sy;
+        mesh_builder->pVertices[i].u3.z *= sz;
+    }
+
+    /* Normals are not affected by Scale */
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_Translate(IDirect3DRMMeshBuilder3 *iface,
+        D3DVALUE tx, D3DVALUE ty, D3DVALUE tz)
+{
+    FIXME("iface %p, tx %.8e, ty %.8e, tz %.8e stub!\n", iface, tx, ty, tz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetColorSource(IDirect3DRMMeshBuilder3 *iface,
+        D3DRMCOLORSOURCE source)
+{
+    FIXME("iface %p, source %#x stub!\n", iface, source);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetBox(IDirect3DRMMeshBuilder3 *iface, D3DRMBOX *box)
+{
+    FIXME("iface %p, box %p stub!\n", iface, box);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GenerateNormals(IDirect3DRMMeshBuilder3 *iface,
+        D3DVALUE crease, DWORD flags)
+{
+    FIXME("iface %p, crease %.8e, flags %#x stub!\n", iface, crease, flags);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMCOLORSOURCE WINAPI d3drm_mesh_builder3_GetColorSource(IDirect3DRMMeshBuilder3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_AddMesh(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMMesh *mesh)
+{
+    FIXME("iface %p, mesh %p stub!\n", iface, mesh);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_AddMeshBuilder(IDirect3DRMMeshBuilder3 *iface,
+        IDirect3DRMMeshBuilder3 *mesh_builder, DWORD flags)
+{
+    FIXME("iface %p, mesh_builder %p, flags %#x stub!\n", iface, mesh_builder, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_AddFrame(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMFrame3 *frame)
+{
+    FIXME("iface %p, frame %p stub!\n", iface, frame);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_AddFace(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMFace2 *face)
+{
+    FIXME("iface %p, face %p stub!\n", iface, face);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_AddFaces(IDirect3DRMMeshBuilder3 *iface,
+        DWORD vertex_count, D3DVECTOR *vertices, DWORD normal_count, D3DVECTOR *normals,
+        DWORD *face_data, IDirect3DRMFaceArray **array)
+{
+    FIXME("iface %p, vertex_count %u, vertices %p, normal_count %u, normals %p, face_data %p array %p stub!\n",
+            iface, vertex_count, vertices, normal_count, normals, face_data, array);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_ReserveSpace(IDirect3DRMMeshBuilder3 *iface,
+        DWORD vertex_count, DWORD normal_count, DWORD face_count)
+{
+    FIXME("iface %p, vertex_count %u, normal_count %u, face_count %u stub!\n",
+            iface, vertex_count, normal_count, face_count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetColorRGB(IDirect3DRMMeshBuilder3 *iface,
+        D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p, red %.8e, green %.8e, blue %.8e.\n", iface, red, green, blue);
+
+    mesh_builder->color = RGBA_MAKE((BYTE)(red * 255.0f), (BYTE)(green * 255.0f), (BYTE)(blue * 255.0f), 0xff);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetColor(IDirect3DRMMeshBuilder3 *iface, D3DCOLOR color)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p, color 0x%08x.\n", iface, color);
+
+    mesh_builder->color = color;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetTexture(IDirect3DRMMeshBuilder3 *iface,
+        IDirect3DRMTexture3 *texture)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p, texture %p.\n", iface, texture);
+
+    if (texture)
+        IDirect3DRMTexture3_AddRef(texture);
+    if (mesh_builder->texture)
+        IDirect3DRMTexture3_Release(mesh_builder->texture);
+    mesh_builder->texture = texture;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetMaterial(IDirect3DRMMeshBuilder3 *iface,
+        IDirect3DRMMaterial2 *material)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p, material %p.\n", iface, material);
+
+    if (material)
+        IDirect3DRMTexture2_AddRef(material);
+    if (mesh_builder->material)
+        IDirect3DRMTexture2_Release(mesh_builder->material);
+    mesh_builder->material = material;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetTextureTopology(IDirect3DRMMeshBuilder3 *iface,
+        BOOL wrap_u, BOOL wrap_v)
+{
+    FIXME("iface %p, wrap_u %#x, wrap_v %#x stub!\n", iface, wrap_u, wrap_v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetQuality(IDirect3DRMMeshBuilder3 *iface,
+        D3DRMRENDERQUALITY quality)
+{
+    FIXME("iface %p, quality %#x stub!\n", iface, quality);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetPerspective(IDirect3DRMMeshBuilder3 *iface,
+        BOOL enable)
+{
+    FIXME("iface %p, enable %#x stub!\n", iface, enable);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetVertex(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, index %u, x %.8e, y %.8e, z %.8e stub!\n", iface, index, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetNormal(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, index %u, x %.8e, y %.8e, z %.8e stub!\n", iface, index, x, y, z);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetTextureCoordinates(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, D3DVALUE u, D3DVALUE v)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p, index %u, u %.8e, v %.8e.\n", iface, index, u, v);
+
+    if (index >= mesh_builder->nb_coords2d)
+        return D3DRMERR_BADVALUE;
+
+    mesh_builder->pCoords2d[index].u = u;
+    mesh_builder->pCoords2d[index].v = v;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetVertexColor(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, D3DCOLOR color)
+{
+    FIXME("iface %p, index %u, color 0x%08x stub!\n", iface, index, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetVertexColorRGB(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    FIXME("iface %p, index %u, red %.8e, green %.8e, blue %.8e stub!\n",
+            iface, index, red, green, blue);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetFaces(IDirect3DRMMeshBuilder3 *iface,
+        IDirect3DRMFaceArray **array)
+{
+    FIXME("iface %p, array %p stub!\n", iface, array);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetGeometry(IDirect3DRMMeshBuilder3 *iface,
+        DWORD *vertex_count, D3DVECTOR *vertices, DWORD *normal_count, D3DVECTOR *normals,
+        DWORD *face_data_size, DWORD *face_data)
+{
+    FIXME("iface %p, vertex_count %p, vertices %p, normal_count %p, normals %p, "
+            "face_data_size %p, face_data %p stub!\n",
+            iface, vertex_count, vertices, normal_count, normals, face_data_size, face_data);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetTextureCoordinates(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, D3DVALUE *u, D3DVALUE *v)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p, index %u, u %p, v %p.\n", iface, index, u, v);
+
+    if (index >= mesh_builder->nb_coords2d)
+        return D3DRMERR_BADVALUE;
+
+    *u = mesh_builder->pCoords2d[index].u;
+    *v = mesh_builder->pCoords2d[index].v;
+
+    return D3DRM_OK;
+}
+
+static int WINAPI d3drm_mesh_builder3_AddVertex(IDirect3DRMMeshBuilder3 *iface,
+        D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, x %.8e, y %.8e, z %.8e stub!\n", iface, x, y, z);
+
+    return 0;
+}
+
+static int WINAPI d3drm_mesh_builder3_AddNormal(IDirect3DRMMeshBuilder3 *iface,
+        D3DVALUE x, D3DVALUE y, D3DVALUE z)
+{
+    FIXME("iface %p, x %.8e, y %.8e, z %.8e stub!\n", iface, x, y, z);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_CreateFace(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMFace2 **face)
+{
+    TRACE("iface %p, face %p.\n", iface, face);
+
+    return Direct3DRMFace_create(&IID_IDirect3DRMFace2, (IUnknown **)face);
+}
+
+static D3DRMRENDERQUALITY WINAPI d3drm_mesh_builder3_GetQuality(IDirect3DRMMeshBuilder3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static BOOL WINAPI d3drm_mesh_builder3_GetPerspective(IDirect3DRMMeshBuilder3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return FALSE;
+}
+
+static int WINAPI d3drm_mesh_builder3_GetFaceCount(IDirect3DRMMeshBuilder3 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return mesh_builder->nb_faces;
+}
+
+static int WINAPI d3drm_mesh_builder3_GetVertexCount(IDirect3DRMMeshBuilder3 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return mesh_builder->nb_vertices;
+}
+
+static D3DCOLOR WINAPI d3drm_mesh_builder3_GetVertexColor(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index)
+{
+    FIXME("iface %p, index %u stub!\n", iface, index);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_CreateMesh(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMMesh **mesh)
+{
+    struct d3drm_mesh_builder *This = impl_from_IDirect3DRMMeshBuilder3(iface);
+    HRESULT hr;
+    D3DRMGROUPINDEX group;
+
+    TRACE("iface %p, mesh %p.\n", iface, mesh);
+
+    if (!mesh)
+        return E_POINTER;
+
+    hr = Direct3DRMMesh_create(mesh);
+    if (FAILED(hr))
+        return hr;
+
+    /* If there is mesh data, create a group and put data inside */
+    if (This->nb_vertices)
+    {
+        DWORD i, j;
+        int k;
+        D3DRMVERTEX* vertices;
+
+        vertices = HeapAlloc(GetProcessHeap(), 0, This->nb_vertices * sizeof(D3DRMVERTEX));
+        if (!vertices)
+        {
+            IDirect3DRMMesh_Release(*mesh);
+            return E_OUTOFMEMORY;
+        }
+        for (i = 0; i < This->nb_vertices; i++)
+            vertices[i].position = This->pVertices[i];
+        hr = IDirect3DRMMesh_SetVertices(*mesh, 0, 0, This->nb_vertices, vertices);
+        HeapFree(GetProcessHeap(), 0, vertices);
+
+        /* Groups are in reverse order compared to materials list in X file */
+        for (k = This->nb_materials - 1; k >= 0; k--)
+        {
+            unsigned* face_data;
+            unsigned* out_ptr;
+            DWORD* in_ptr = This->pFaceData;
+            ULONG vertex_per_face = 0;
+            BOOL* used_vertices;
+            unsigned nb_vertices = 0;
+            unsigned nb_faces = 0;
+
+            used_vertices = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->face_data_size * sizeof(*used_vertices));
+            if (!used_vertices)
+            {
+                IDirect3DRMMesh_Release(*mesh);
+                return E_OUTOFMEMORY;
+            }
+
+            face_data = HeapAlloc(GetProcessHeap(), 0, This->face_data_size * sizeof(*face_data));
+            if (!face_data)
+            {
+                HeapFree(GetProcessHeap(), 0, used_vertices);
+                IDirect3DRMMesh_Release(*mesh);
+                return E_OUTOFMEMORY;
+            }
+            out_ptr = face_data;
+
+            /* If all faces have the same number of vertex, set vertex_per_face */
+            for (i = 0; i < This->nb_faces; i++)
+            {
+                /* Process only faces belonging to the group */
+                if (This->material_indices[i] == k)
+                {
+                    if (vertex_per_face && (vertex_per_face != *in_ptr))
+                        break;
+                    vertex_per_face = *in_ptr;
+                }
+                in_ptr += 1 + *in_ptr * 2;
+            }
+            if (i != This->nb_faces)
+                vertex_per_face = 0;
+
+            /* Put only vertex indices */
+            in_ptr = This->pFaceData;
+            for (i = 0; i < This->nb_faces; i++)
+            {
+                DWORD nb_indices = *in_ptr++;
+
+                /* Skip faces not belonging to the group */
+                if (This->material_indices[i] != k)
+                {
+                    in_ptr += 2 * nb_indices;
+                    continue;
+                }
+
+                /* Don't put nb indices when vertex_per_face is set */
+                if (vertex_per_face)
+                    *out_ptr++ = nb_indices;
+
+                for (j = 0; j < nb_indices; j++)
+                {
+                    *out_ptr = *in_ptr++;
+                    used_vertices[*out_ptr++] = TRUE;
+                    /* Skip normal index */
+                    in_ptr++;
+                }
+
+                nb_faces++;
+            }
+
+            for (i = 0; i < This->nb_vertices; i++)
+                if (used_vertices[i])
+                    nb_vertices++;
+
+            hr = IDirect3DRMMesh_AddGroup(*mesh, nb_vertices, nb_faces, vertex_per_face, face_data, &group);
+            HeapFree(GetProcessHeap(), 0, used_vertices);
+            HeapFree(GetProcessHeap(), 0, face_data);
+            if (SUCCEEDED(hr))
+                hr = IDirect3DRMMesh_SetGroupColor(*mesh, group, This->materials[k].color);
+            if (SUCCEEDED(hr))
+                hr = IDirect3DRMMesh_SetGroupMaterial(*mesh, group,
+                        (IDirect3DRMMaterial *)This->materials[k].material);
+            if (SUCCEEDED(hr) && This->materials[k].texture)
+            {
+                IDirect3DRMTexture *texture;
+
+                IDirect3DRMTexture3_QueryInterface(This->materials[k].texture,
+                        &IID_IDirect3DRMTexture, (void **)&texture);
+                hr = IDirect3DRMMesh_SetGroupTexture(*mesh, group, texture);
+                IDirect3DRMTexture_Release(texture);
+            }
+            if (FAILED(hr))
+            {
+                IDirect3DRMMesh_Release(*mesh);
+                return hr;
+            }
+        }
+    }
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetFace(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, IDirect3DRMFace2 **face)
+{
+    FIXME("iface %p, index %u, face %p stub!\n", iface, index, face);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetVertex(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, D3DVECTOR *vector)
+{
+    FIXME("iface %p, index %u, vector %p stub!\n", iface, index, vector);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetNormal(IDirect3DRMMeshBuilder3 *iface,
+        DWORD index, D3DVECTOR *vector)
+{
+    FIXME("iface %p, index %u, vector %p stub!\n", iface, index, vector);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_DeleteVertices(IDirect3DRMMeshBuilder3 *iface,
+        DWORD start_idx, DWORD count)
+{
+    FIXME("iface %p, start_idx %u, count %u stub!\n", iface, start_idx, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_DeleteNormals(IDirect3DRMMeshBuilder3 *iface,
+        DWORD start_idx, DWORD count)
+{
+    FIXME("iface %p, start_idx %u, count %u stub!\n", iface, start_idx, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_DeleteFace(IDirect3DRMMeshBuilder3 *iface, IDirect3DRMFace2 *face)
+{
+    FIXME("iface %p, face %p stub!\n", iface, face);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_Empty(IDirect3DRMMeshBuilder3 *iface, DWORD flags)
+{
+    FIXME("iface %p, flags %#x stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_Optimize(IDirect3DRMMeshBuilder3 *iface, DWORD flags)
+{
+    FIXME("iface %p, flags %#x stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_AddFacesIndexed(IDirect3DRMMeshBuilder3 *iface,
+        DWORD flags, DWORD *indices, DWORD *start_idx, DWORD *count)
+{
+    FIXME("iface %p, flags %#x, indices %p, start_idx %p, count %p stub!\n",
+            iface, flags, indices, start_idx, count);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_CreateSubMesh(IDirect3DRMMeshBuilder3 *iface, IUnknown **mesh)
+{
+    FIXME("iface %p, mesh %p stub!\n", iface, mesh);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetParentMesh(IDirect3DRMMeshBuilder3 *iface,
+        DWORD flags, IUnknown **parent)
+{
+    FIXME("iface %p, flags %#x, parent %p stub!\n", iface, flags, parent);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetSubMeshes(IDirect3DRMMeshBuilder3 *iface,
+        DWORD *count, IUnknown **meshes)
+{
+    FIXME("iface %p, count %p, meshes %p stub!\n", iface, count, meshes);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_DeleteSubMesh(IDirect3DRMMeshBuilder3 *iface, IUnknown *mesh)
+{
+    FIXME("iface %p, mesh %p stub!\n", iface, mesh);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_Enable(IDirect3DRMMeshBuilder3 *iface, DWORD index)
+{
+    FIXME("iface %p, index %u stub!\n", iface, index);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetEnable(IDirect3DRMMeshBuilder3 *iface, DWORD *indices)
+{
+    FIXME("iface %p, indices %p stub!\n", iface, indices);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_AddTriangles(IDirect3DRMMeshBuilder3 *iface,
+        DWORD flags, DWORD format, DWORD vertex_count, void *data)
+{
+    FIXME("iface %p, flags %#x, format %#x, vertex_count %u, data %p stub!\n",
+            iface, flags, format, vertex_count, data);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetVertices(IDirect3DRMMeshBuilder3 *iface,
+        DWORD start_idx, DWORD count, D3DVECTOR *vector)
+{
+    FIXME("iface %p, start_idx %u, count %u, vector %p stub!\n", iface, start_idx, count, vector);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetVertices(IDirect3DRMMeshBuilder3 *iface,
+        DWORD start_idx, DWORD *vertex_count, D3DVECTOR *vertices)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+    DWORD count = mesh_builder->nb_vertices - start_idx;
+
+    TRACE("iface %p, start_idx %u, vertex_count %p, vertices %p.\n",
+            iface, start_idx, vertex_count, vertices);
+
+    if (vertex_count)
+        *vertex_count = count;
+    if (vertices && mesh_builder->nb_vertices)
+        memcpy(vertices, mesh_builder->pVertices + start_idx, count * sizeof(*vertices));
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_SetNormals(IDirect3DRMMeshBuilder3 *iface,
+        DWORD start_idx, DWORD count, D3DVECTOR *vector)
+{
+    FIXME("iface %p, start_idx %u, count %u, vector %p stub!\n",
+            iface, start_idx, count, vector);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_builder3_GetNormals(IDirect3DRMMeshBuilder3 *iface,
+        DWORD start_idx, DWORD *normal_count, D3DVECTOR *normals)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+    DWORD count = mesh_builder->nb_normals - start_idx;
+
+    TRACE("iface %p, start_idx %u, normal_count %p, normals %p stub!\n",
+            iface, start_idx, normal_count, normals);
+
+    if (normal_count)
+        *normal_count = count;
+    if (normals && mesh_builder->nb_normals)
+        memcpy(normals, mesh_builder->pNormals + start_idx, count * sizeof(*normals));
+
+    return D3DRM_OK;
+}
+
+static int WINAPI d3drm_mesh_builder3_GetNormalCount(IDirect3DRMMeshBuilder3 *iface)
+{
+    struct d3drm_mesh_builder *mesh_builder = impl_from_IDirect3DRMMeshBuilder3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return mesh_builder->nb_normals;
+}
+
+static const struct IDirect3DRMMeshBuilder3Vtbl d3drm_mesh_builder3_vtbl =
+{
+    d3drm_mesh_builder3_QueryInterface,
+    d3drm_mesh_builder3_AddRef,
+    d3drm_mesh_builder3_Release,
+    d3drm_mesh_builder3_Clone,
+    d3drm_mesh_builder3_AddDestroyCallback,
+    d3drm_mesh_builder3_DeleteDestroyCallback,
+    d3drm_mesh_builder3_SetAppData,
+    d3drm_mesh_builder3_GetAppData,
+    d3drm_mesh_builder3_SetName,
+    d3drm_mesh_builder3_GetName,
+    d3drm_mesh_builder3_GetClassName,
+    d3drm_mesh_builder3_Load,
+    d3drm_mesh_builder3_Save,
+    d3drm_mesh_builder3_Scale,
+    d3drm_mesh_builder3_Translate,
+    d3drm_mesh_builder3_SetColorSource,
+    d3drm_mesh_builder3_GetBox,
+    d3drm_mesh_builder3_GenerateNormals,
+    d3drm_mesh_builder3_GetColorSource,
+    d3drm_mesh_builder3_AddMesh,
+    d3drm_mesh_builder3_AddMeshBuilder,
+    d3drm_mesh_builder3_AddFrame,
+    d3drm_mesh_builder3_AddFace,
+    d3drm_mesh_builder3_AddFaces,
+    d3drm_mesh_builder3_ReserveSpace,
+    d3drm_mesh_builder3_SetColorRGB,
+    d3drm_mesh_builder3_SetColor,
+    d3drm_mesh_builder3_SetTexture,
+    d3drm_mesh_builder3_SetMaterial,
+    d3drm_mesh_builder3_SetTextureTopology,
+    d3drm_mesh_builder3_SetQuality,
+    d3drm_mesh_builder3_SetPerspective,
+    d3drm_mesh_builder3_SetVertex,
+    d3drm_mesh_builder3_SetNormal,
+    d3drm_mesh_builder3_SetTextureCoordinates,
+    d3drm_mesh_builder3_SetVertexColor,
+    d3drm_mesh_builder3_SetVertexColorRGB,
+    d3drm_mesh_builder3_GetFaces,
+    d3drm_mesh_builder3_GetGeometry,
+    d3drm_mesh_builder3_GetTextureCoordinates,
+    d3drm_mesh_builder3_AddVertex,
+    d3drm_mesh_builder3_AddNormal,
+    d3drm_mesh_builder3_CreateFace,
+    d3drm_mesh_builder3_GetQuality,
+    d3drm_mesh_builder3_GetPerspective,
+    d3drm_mesh_builder3_GetFaceCount,
+    d3drm_mesh_builder3_GetVertexCount,
+    d3drm_mesh_builder3_GetVertexColor,
+    d3drm_mesh_builder3_CreateMesh,
+    d3drm_mesh_builder3_GetFace,
+    d3drm_mesh_builder3_GetVertex,
+    d3drm_mesh_builder3_GetNormal,
+    d3drm_mesh_builder3_DeleteVertices,
+    d3drm_mesh_builder3_DeleteNormals,
+    d3drm_mesh_builder3_DeleteFace,
+    d3drm_mesh_builder3_Empty,
+    d3drm_mesh_builder3_Optimize,
+    d3drm_mesh_builder3_AddFacesIndexed,
+    d3drm_mesh_builder3_CreateSubMesh,
+    d3drm_mesh_builder3_GetParentMesh,
+    d3drm_mesh_builder3_GetSubMeshes,
+    d3drm_mesh_builder3_DeleteSubMesh,
+    d3drm_mesh_builder3_Enable,
+    d3drm_mesh_builder3_GetEnable,
+    d3drm_mesh_builder3_AddTriangles,
+    d3drm_mesh_builder3_SetVertices,
+    d3drm_mesh_builder3_GetVertices,
+    d3drm_mesh_builder3_SetNormals,
+    d3drm_mesh_builder3_GetNormals,
+    d3drm_mesh_builder3_GetNormalCount,
+};
+
+HRESULT Direct3DRMMeshBuilder_create(REFIID riid, IUnknown **out)
+{
+    struct d3drm_mesh_builder *object;
+
+    TRACE("riid %s, out %p.\n", debugstr_guid(riid), out);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMMeshBuilder2_iface.lpVtbl = &d3drm_mesh_builder2_vtbl;
+    object->IDirect3DRMMeshBuilder3_iface.lpVtbl = &d3drm_mesh_builder3_vtbl;
+    object->ref = 1;
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMMeshBuilder3))
+        *out = (IUnknown *)&object->IDirect3DRMMeshBuilder3_iface;
+    else
+        *out = (IUnknown *)&object->IDirect3DRMMeshBuilder2_iface;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_QueryInterface(IDirect3DRMMesh *iface, REFIID riid, void **out)
+{
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMMesh)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        IDirect3DRMMesh_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI d3drm_mesh_AddRef(IDirect3DRMMesh *iface)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+    ULONG refcount = InterlockedIncrement(&mesh->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_mesh_Release(IDirect3DRMMesh *iface)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+    ULONG refcount = InterlockedDecrement(&mesh->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        DWORD i;
+
+        for (i = 0; i < mesh->nb_groups; ++i)
+        {
+            HeapFree(GetProcessHeap(), 0, mesh->groups[i].vertices);
+            HeapFree(GetProcessHeap(), 0, mesh->groups[i].face_data);
+            if (mesh->groups[i].material)
+                IDirect3DRMMaterial2_Release(mesh->groups[i].material);
+            if (mesh->groups[i].texture)
+                IDirect3DRMTexture3_Release(mesh->groups[i].texture);
+        }
+        HeapFree(GetProcessHeap(), 0, mesh->groups);
+        HeapFree(GetProcessHeap(), 0, mesh);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_mesh_Clone(IDirect3DRMMesh *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_AddDestroyCallback(IDirect3DRMMesh *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_DeleteDestroyCallback(IDirect3DRMMesh *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetAppData(IDirect3DRMMesh *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_mesh_GetAppData(IDirect3DRMMesh *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetName(IDirect3DRMMesh *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_GetName(IDirect3DRMMesh *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_GetClassName(IDirect3DRMMesh *iface, DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Mesh") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Mesh");
+    *size = sizeof("Mesh");
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_Scale(IDirect3DRMMesh *iface,
+        D3DVALUE sx, D3DVALUE sy, D3DVALUE sz)
+{
+    FIXME("iface %p, sx %.8e, sy %.8e, sz %.8e stub!\n", iface, sx, sy, sz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_Translate(IDirect3DRMMesh *iface,
+        D3DVALUE tx, D3DVALUE ty, D3DVALUE tz)
+{
+    FIXME("iface %p, tx %.8e, ty %.8e, tz %.8e stub!\n", iface, tx, ty, tz);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_GetBox(IDirect3DRMMesh *iface, D3DRMBOX *box)
+{
+    FIXME("iface %p, box %p stub!\n", iface, box);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_AddGroup(IDirect3DRMMesh *iface, unsigned vertex_count,
+        unsigned face_count, unsigned vertex_per_face, unsigned *face_data, D3DRMGROUPINDEX *id)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+    struct mesh_group *group;
+
+    TRACE("iface %p, vertex_count %u, face_count %u, vertex_per_face %u, face_data %p, id %p.\n",
+            iface, vertex_count, face_count, vertex_per_face, face_data, id);
+
+    if (!face_data || !id)
+        return E_POINTER;
+
+    if ((mesh->nb_groups + 1) > mesh->groups_capacity)
+    {
+        struct mesh_group *groups;
+        ULONG new_capacity;
+
+        if (!mesh->groups_capacity)
+        {
+            new_capacity = 16;
+            groups = HeapAlloc(GetProcessHeap(), 0, new_capacity * sizeof(*groups));
+        }
+        else
+        {
+            new_capacity = mesh->groups_capacity * 2;
+            groups = HeapReAlloc(GetProcessHeap(), 0, mesh->groups, new_capacity * sizeof(*groups));
+        }
+
+        if (!groups)
+            return E_OUTOFMEMORY;
+
+        mesh->groups_capacity = new_capacity;
+        mesh->groups = groups;
+    }
+
+    group = mesh->groups + mesh->nb_groups;
+
+    group->vertices = HeapAlloc(GetProcessHeap(), 0, vertex_count * sizeof(D3DRMVERTEX));
+    if (!group->vertices)
+        return E_OUTOFMEMORY;
+    group->nb_vertices = vertex_count;
+    group->nb_faces = face_count;
+    group->vertex_per_face = vertex_per_face;
+
+    if (vertex_per_face)
+    {
+        group->face_data_size = face_count * vertex_per_face;
+    }
+    else
+    {
+        unsigned i;
+        unsigned nb_indices;
+        unsigned* face_data_ptr = face_data;
+        group->face_data_size = 0;
+
+        for (i = 0; i < face_count; i++)
+        {
+            nb_indices = *face_data_ptr;
+            group->face_data_size += nb_indices + 1;
+            face_data_ptr += nb_indices;
+        }
+    }
+
+    group->face_data = HeapAlloc(GetProcessHeap(), 0, group->face_data_size * sizeof(unsigned));
+    if (!group->face_data)
+    {
+        HeapFree(GetProcessHeap(), 0 , group->vertices);
+        return E_OUTOFMEMORY;
+    }
+
+    memcpy(group->face_data, face_data, group->face_data_size * sizeof(unsigned));
+
+    group->material = NULL;
+    group->texture = NULL;
+
+    *id = mesh->nb_groups++;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetVertices(IDirect3DRMMesh *iface, D3DRMGROUPINDEX group_id,
+        unsigned int start_idx, unsigned int count, D3DRMVERTEX *values)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, group_id %#x, start_idx %u, count %u, values %p.\n",
+            iface, group_id, start_idx, count, values);
+
+    if (group_id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    if ((start_idx + count - 1) >= mesh->groups[group_id].nb_vertices)
+        return D3DRMERR_BADVALUE;
+
+    if (!values)
+        return E_POINTER;
+
+    memcpy(mesh->groups[group_id].vertices + start_idx, values, count * sizeof(*values));
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetGroupColor(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id, D3DCOLOR color)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, id %#x, color 0x%08x.\n", iface, id, color);
+
+    if (id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    mesh->groups[id].color = color;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetGroupColorRGB(IDirect3DRMMesh *iface,
+        D3DRMGROUPINDEX id, D3DVALUE red, D3DVALUE green, D3DVALUE blue)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, id %#x, red %.8e, green %.8e, blue %.8e.\n", iface, id, red, green, blue);
+
+    if (id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    mesh->groups[id].color = RGBA_MAKE((BYTE)(red * 255.0f), (BYTE)(green * 255.0f), (BYTE)(blue * 255.0f), 0xff);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetGroupMapping(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id, D3DRMMAPPING value)
+{
+    FIXME("iface %p, id %#x, value %#x stub!\n", iface, id, value);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetGroupQuality(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id, D3DRMRENDERQUALITY value)
+{
+    FIXME("iface %p, id %#x, value %#x stub!\n", iface, id, value);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetGroupMaterial(IDirect3DRMMesh *iface,
+        D3DRMGROUPINDEX id, IDirect3DRMMaterial *material)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, id %#x, material %p.\n", iface, id, material);
+
+    if (id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    if (mesh->groups[id].material)
+        IDirect3DRMMaterial2_Release(mesh->groups[id].material);
+
+    mesh->groups[id].material = (IDirect3DRMMaterial2 *)material;
+
+    if (material)
+        IDirect3DRMMaterial2_AddRef(mesh->groups[id].material);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_SetGroupTexture(IDirect3DRMMesh *iface,
+        D3DRMGROUPINDEX id, IDirect3DRMTexture *texture)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, id %#x, texture %p.\n", iface, id, texture);
+
+    if (id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    if (mesh->groups[id].texture)
+        IDirect3DRMTexture3_Release(mesh->groups[id].texture);
+
+    if (!texture)
+    {
+        mesh->groups[id].texture = NULL;
+        return D3DRM_OK;
+    }
+
+    return IDirect3DRMTexture3_QueryInterface(texture, &IID_IDirect3DRMTexture, (void **)&mesh->groups[id].texture);
+}
+
+static DWORD WINAPI d3drm_mesh_GetGroupCount(IDirect3DRMMesh *iface)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return mesh->nb_groups;
+}
+
+static HRESULT WINAPI d3drm_mesh_GetGroup(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id, unsigned *vertex_count,
+        unsigned *face_count, unsigned *vertex_per_face, DWORD *face_data_size, unsigned *face_data)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, id %#x, vertex_count %p, face_count %p, vertex_per_face %p, face_data_size %p, face_data %p.\n",
+            iface, id, vertex_count, face_count, vertex_per_face, face_data_size,face_data);
+
+    if (id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    if (vertex_count)
+        *vertex_count = mesh->groups[id].nb_vertices;
+    if (face_count)
+        *face_count = mesh->groups[id].nb_faces;
+    if (vertex_per_face)
+        *vertex_per_face = mesh->groups[id].vertex_per_face;
+    if (face_data_size)
+        *face_data_size = mesh->groups[id].face_data_size;
+    if (face_data)
+        memcpy(face_data, mesh->groups[id].face_data, mesh->groups[id].face_data_size * sizeof(*face_data));
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_GetVertices(IDirect3DRMMesh *iface,
+        D3DRMGROUPINDEX group_id, DWORD start_idx, DWORD count, D3DRMVERTEX *vertices)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, group_id %#x, start_idx %u, count %u, vertices %p.\n",
+            iface, group_id, start_idx, count, vertices);
+
+    if (group_id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    if ((start_idx + count - 1) >= mesh->groups[group_id].nb_vertices)
+        return D3DRMERR_BADVALUE;
+
+    if (!vertices)
+        return E_POINTER;
+
+    memcpy(vertices, mesh->groups[group_id].vertices + start_idx, count * sizeof(*vertices));
+
+    return D3DRM_OK;
+}
+
+static D3DCOLOR WINAPI d3drm_mesh_GetGroupColor(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, id %#x.\n", iface, id);
+
+    return mesh->groups[id].color;
+}
+
+static D3DRMMAPPING WINAPI d3drm_mesh_GetGroupMapping(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id)
+{
+    FIXME("iface %p, id %#x stub!\n", iface, id);
+
+    return 0;
+}
+static D3DRMRENDERQUALITY WINAPI d3drm_mesh_GetGroupQuality(IDirect3DRMMesh *iface, D3DRMGROUPINDEX id)
+{
+    FIXME("iface %p, id %#x stub!\n", iface, id);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_mesh_GetGroupMaterial(IDirect3DRMMesh *iface,
+        D3DRMGROUPINDEX id, IDirect3DRMMaterial **material)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, id %#x, material %p.\n", iface, id, material);
+
+    if (id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    if (!material)
+        return E_POINTER;
+
+    if (mesh->groups[id].material)
+        IDirect3DRMTexture_QueryInterface(mesh->groups[id].material, &IID_IDirect3DRMMaterial, (void **)material);
+    else
+        *material = NULL;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_mesh_GetGroupTexture(IDirect3DRMMesh *iface,
+        D3DRMGROUPINDEX id, IDirect3DRMTexture **texture)
+{
+    struct d3drm_mesh *mesh = impl_from_IDirect3DRMMesh(iface);
+
+    TRACE("iface %p, id %#x, texture %p.\n", iface, id, texture);
+
+    if (id >= mesh->nb_groups)
+        return D3DRMERR_BADVALUE;
+
+    if (!texture)
+        return E_POINTER;
+
+    if (mesh->groups[id].texture)
+        IDirect3DRMTexture_QueryInterface(mesh->groups[id].texture, &IID_IDirect3DRMTexture, (void **)texture);
+    else
+        *texture = NULL;
+
+    return D3DRM_OK;
+}
+
+static const struct IDirect3DRMMeshVtbl d3drm_mesh_vtbl =
+{
+    d3drm_mesh_QueryInterface,
+    d3drm_mesh_AddRef,
+    d3drm_mesh_Release,
+    d3drm_mesh_Clone,
+    d3drm_mesh_AddDestroyCallback,
+    d3drm_mesh_DeleteDestroyCallback,
+    d3drm_mesh_SetAppData,
+    d3drm_mesh_GetAppData,
+    d3drm_mesh_SetName,
+    d3drm_mesh_GetName,
+    d3drm_mesh_GetClassName,
+    d3drm_mesh_Scale,
+    d3drm_mesh_Translate,
+    d3drm_mesh_GetBox,
+    d3drm_mesh_AddGroup,
+    d3drm_mesh_SetVertices,
+    d3drm_mesh_SetGroupColor,
+    d3drm_mesh_SetGroupColorRGB,
+    d3drm_mesh_SetGroupMapping,
+    d3drm_mesh_SetGroupQuality,
+    d3drm_mesh_SetGroupMaterial,
+    d3drm_mesh_SetGroupTexture,
+    d3drm_mesh_GetGroupCount,
+    d3drm_mesh_GetGroup,
+    d3drm_mesh_GetVertices,
+    d3drm_mesh_GetGroupColor,
+    d3drm_mesh_GetGroupMapping,
+    d3drm_mesh_GetGroupQuality,
+    d3drm_mesh_GetGroupMaterial,
+    d3drm_mesh_GetGroupTexture,
+};
+
+HRESULT Direct3DRMMesh_create(IDirect3DRMMesh **mesh)
+{
+    struct d3drm_mesh *object;
+
+    TRACE("mesh %p.\n", mesh);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMMesh_iface.lpVtbl = &d3drm_mesh_vtbl;
+    object->ref = 1;
+
+    *mesh = &object->IDirect3DRMMesh_iface;
+
+    return S_OK;
+}
diff --git a/reactos/dll/directx/wine/d3drm/texture.c b/reactos/dll/directx/wine/d3drm/texture.c
new file mode 100644 (file)
index 0000000..fb580a1
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * Implementation of IDirect3DRMTextureX interfaces
+ *
+ * Copyright 2012 Christian Costa
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+struct d3drm_texture
+{
+    IDirect3DRMTexture2 IDirect3DRMTexture2_iface;
+    IDirect3DRMTexture3 IDirect3DRMTexture3_iface;
+    LONG ref;
+    DWORD app_data;
+};
+
+static inline struct d3drm_texture *impl_from_IDirect3DRMTexture2(IDirect3DRMTexture2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_texture, IDirect3DRMTexture2_iface);
+}
+
+static inline struct d3drm_texture *impl_from_IDirect3DRMTexture3(IDirect3DRMTexture3 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_texture, IDirect3DRMTexture3_iface);
+}
+
+static HRESULT WINAPI d3drm_texture2_QueryInterface(IDirect3DRMTexture2 *iface, REFIID riid, void **out)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture2(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMTexture2)
+            || IsEqualGUID(riid, &IID_IDirect3DRMTexture)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *out = &texture->IDirect3DRMTexture2_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRMTexture3))
+    {
+        *out = &texture->IDirect3DRMTexture3_iface;
+    }
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI d3drm_texture2_AddRef(IDirect3DRMTexture2 *iface)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture2(iface);
+    ULONG refcount = InterlockedIncrement(&texture->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_texture2_Release(IDirect3DRMTexture2 *iface)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture2(iface);
+    ULONG refcount = InterlockedDecrement(&texture->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+        HeapFree(GetProcessHeap(), 0, texture);
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_texture2_Clone(IDirect3DRMTexture2 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_AddDestroyCallback(IDirect3DRMTexture2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_DeleteDestroyCallback(IDirect3DRMTexture2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_SetAppData(IDirect3DRMTexture2 *iface, DWORD data)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture2(iface);
+
+    TRACE("iface %p, data %#x.\n", iface, data);
+
+    return IDirect3DRMTexture3_SetAppData(&texture->IDirect3DRMTexture3_iface, data);
+}
+
+static DWORD WINAPI d3drm_texture2_GetAppData(IDirect3DRMTexture2 *iface)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMTexture3_GetAppData(&texture->IDirect3DRMTexture3_iface);
+}
+
+static HRESULT WINAPI d3drm_texture2_SetName(IDirect3DRMTexture2 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_GetName(IDirect3DRMTexture2 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_GetClassName(IDirect3DRMTexture2 *iface, DWORD *size, char *name)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture2(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    return IDirect3DRMTexture3_GetClassName(&texture->IDirect3DRMTexture3_iface, size, name);
+}
+
+static HRESULT WINAPI d3drm_texture2_InitFromFile(IDirect3DRMTexture2 *iface, const char *filename)
+{
+    FIXME("iface %p, filename %s stub!\n", iface, debugstr_a(filename));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_InitFromSurface(IDirect3DRMTexture2 *iface,
+        IDirectDrawSurface *surface)
+{
+    FIXME("iface %p, surface %p stub!\n", iface, surface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_InitFromResource(IDirect3DRMTexture2 *iface, HRSRC resource)
+{
+    FIXME("iface %p, resource %p stub!\n", iface, resource);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_Changed(IDirect3DRMTexture2 *iface, BOOL pixels, BOOL palette)
+{
+    FIXME("iface %p, pixels %#x, palette %#x stub!\n", iface, pixels, palette);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_SetColors(IDirect3DRMTexture2 *iface, DWORD max_colors)
+{
+    FIXME("iface %p, max_colors %u stub!\n", iface, max_colors);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_SetShades(IDirect3DRMTexture2 *iface, DWORD max_shades)
+{
+    FIXME("iface %p, max_shades %u stub!\n", iface, max_shades);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_SetDecalSize(IDirect3DRMTexture2 *iface, D3DVALUE width, D3DVALUE height)
+{
+    FIXME("iface %p, width %.8e, height %.8e stub!\n", iface, width, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_SetDecalOrigin(IDirect3DRMTexture2 *iface, LONG x, LONG y)
+{
+    FIXME("iface %p, x %d, y %d stub!\n", iface, x, y);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_SetDecalScale(IDirect3DRMTexture2 *iface, DWORD scale)
+{
+    FIXME("iface %p, scale %u stub!\n", iface, scale);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_SetDecalTransparency(IDirect3DRMTexture2 *iface, BOOL transparency)
+{
+    FIXME("iface %p, transparency %#x stub!\n", iface, transparency);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_SetDecalTransparentColor(IDirect3DRMTexture2 *iface, D3DCOLOR color)
+{
+    FIXME("iface %p, color 0x%08x stub!\n", iface, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_GetDecalSize(IDirect3DRMTexture2 *iface, D3DVALUE *width, D3DVALUE *height)
+{
+    FIXME("iface %p, width %p, height %p stub!\n", iface, width, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_GetDecalOrigin(IDirect3DRMTexture2 *iface, LONG *x, LONG *y)
+{
+    FIXME("iface %p, x %p, y %p stub!\n", iface, x, y);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMIMAGE * WINAPI d3drm_texture2_GetImage(IDirect3DRMTexture2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return NULL;
+}
+
+static DWORD WINAPI d3drm_texture2_GetShades(IDirect3DRMTexture2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static DWORD WINAPI d3drm_texture2_GetColors(IDirect3DRMTexture2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static DWORD WINAPI d3drm_texture2_GetDecalScale(IDirect3DRMTexture2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static BOOL WINAPI d3drm_texture2_GetDecalTransparency(IDirect3DRMTexture2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return FALSE;
+}
+
+static D3DCOLOR WINAPI d3drm_texture2_GetDecalTransparentColor(IDirect3DRMTexture2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_texture2_InitFromImage(IDirect3DRMTexture2 *iface, D3DRMIMAGE *image)
+{
+    FIXME("iface %p, image %p stub!\n", iface, image);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_InitFromResource2(IDirect3DRMTexture2 *iface,
+        HMODULE module, const char *name, const char *type)
+{
+    FIXME("iface %p, module %p, name %s, type %s stub!\n",
+            iface, module, debugstr_a(name), debugstr_a(type));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture2_GenerateMIPMap(IDirect3DRMTexture2 *iface, DWORD flags)
+{
+    FIXME("iface %p, flags %#x stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMTexture2Vtbl d3drm_texture2_vtbl =
+{
+    d3drm_texture2_QueryInterface,
+    d3drm_texture2_AddRef,
+    d3drm_texture2_Release,
+    d3drm_texture2_Clone,
+    d3drm_texture2_AddDestroyCallback,
+    d3drm_texture2_DeleteDestroyCallback,
+    d3drm_texture2_SetAppData,
+    d3drm_texture2_GetAppData,
+    d3drm_texture2_SetName,
+    d3drm_texture2_GetName,
+    d3drm_texture2_GetClassName,
+    d3drm_texture2_InitFromFile,
+    d3drm_texture2_InitFromSurface,
+    d3drm_texture2_InitFromResource,
+    d3drm_texture2_Changed,
+    d3drm_texture2_SetColors,
+    d3drm_texture2_SetShades,
+    d3drm_texture2_SetDecalSize,
+    d3drm_texture2_SetDecalOrigin,
+    d3drm_texture2_SetDecalScale,
+    d3drm_texture2_SetDecalTransparency,
+    d3drm_texture2_SetDecalTransparentColor,
+    d3drm_texture2_GetDecalSize,
+    d3drm_texture2_GetDecalOrigin,
+    d3drm_texture2_GetImage,
+    d3drm_texture2_GetShades,
+    d3drm_texture2_GetColors,
+    d3drm_texture2_GetDecalScale,
+    d3drm_texture2_GetDecalTransparency,
+    d3drm_texture2_GetDecalTransparentColor,
+    d3drm_texture2_InitFromImage,
+    d3drm_texture2_InitFromResource2,
+    d3drm_texture2_GenerateMIPMap,
+};
+
+static HRESULT WINAPI d3drm_texture3_QueryInterface(IDirect3DRMTexture3 *iface, REFIID riid, void **out)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture3(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMTexture2)
+            || IsEqualGUID(riid, &IID_IDirect3DRMTexture)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *out = &texture->IDirect3DRMTexture2_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRMTexture3))
+    {
+        *out = &texture->IDirect3DRMTexture3_iface;
+    }
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI d3drm_texture3_AddRef(IDirect3DRMTexture3 *iface)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture3(iface);
+    ULONG refcount = InterlockedIncrement(&texture->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_texture3_Release(IDirect3DRMTexture3 *iface)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture3(iface);
+    ULONG refcount = InterlockedDecrement(&texture->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+        HeapFree(GetProcessHeap(), 0, texture);
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_texture3_Clone(IDirect3DRMTexture3 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_AddDestroyCallback(IDirect3DRMTexture3 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_DeleteDestroyCallback(IDirect3DRMTexture3 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetAppData(IDirect3DRMTexture3 *iface, DWORD data)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture3(iface);
+
+    TRACE("iface %p, data %#x.\n", iface, data);
+
+    texture->app_data = data;
+
+    return D3DRM_OK;
+}
+
+static DWORD WINAPI d3drm_texture3_GetAppData(IDirect3DRMTexture3 *iface)
+{
+    struct d3drm_texture *texture = impl_from_IDirect3DRMTexture3(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return texture->app_data;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetName(IDirect3DRMTexture3 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_GetName(IDirect3DRMTexture3 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_GetClassName(IDirect3DRMTexture3 *iface, DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Texture") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Texture");
+    *size = sizeof("Texture");
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_texture3_InitFromFile(IDirect3DRMTexture3 *iface, const char *filename)
+{
+    FIXME("iface %p, filename %s stub!\n", iface, debugstr_a(filename));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_InitFromSurface(IDirect3DRMTexture3 *iface,
+        IDirectDrawSurface *surface)
+{
+    FIXME("iface %p, surface %p stub!\n", iface, surface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_InitFromResource(IDirect3DRMTexture3 *iface, HRSRC resource)
+{
+    FIXME("iface %p, resource %p stub!\n", iface, resource);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_Changed(IDirect3DRMTexture3 *iface,
+        DWORD flags, DWORD rect_count, RECT *rects)
+{
+    FIXME("iface %p, flags %#x, rect_count %u, rects %p stub!\n", iface, flags, rect_count, rects);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetColors(IDirect3DRMTexture3 *iface, DWORD max_colors)
+{
+    FIXME("iface %p, max_colors %u stub!\n", iface, max_colors);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetShades(IDirect3DRMTexture3 *iface, DWORD max_shades)
+{
+    FIXME("iface %p, max_shades %u stub!\n", iface, max_shades);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetDecalSize(IDirect3DRMTexture3 *iface, D3DVALUE width, D3DVALUE height)
+{
+    FIXME("iface %p, width %.8e, height %.8e stub!\n", iface, width, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetDecalOrigin(IDirect3DRMTexture3 *iface, LONG x, LONG y)
+{
+    FIXME("iface %p, x %d, y %d stub!\n", iface, x, y);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetDecalScale(IDirect3DRMTexture3 *iface, DWORD scale)
+{
+    FIXME("iface %p, scale %u stub!\n", iface, scale);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetDecalTransparency(IDirect3DRMTexture3 *iface, BOOL transparency)
+{
+    FIXME("iface %p, transparency %#x stub!\n", iface, transparency);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetDecalTransparentColor(IDirect3DRMTexture3 *iface, D3DCOLOR color)
+{
+    FIXME("iface %p, color 0x%08x stub!\n", iface, color);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_GetDecalSize(IDirect3DRMTexture3 *iface, D3DVALUE *width, D3DVALUE *height)
+{
+    FIXME("iface %p, width %p, height %p stub!\n", iface, width, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_GetDecalOrigin(IDirect3DRMTexture3 *iface, LONG *x, LONG *y)
+{
+    FIXME("iface %p, x %p, y %p stub!\n", iface, x, y);
+
+    return E_NOTIMPL;
+}
+
+static D3DRMIMAGE * WINAPI d3drm_texture3_GetImage(IDirect3DRMTexture3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return NULL;
+}
+
+static DWORD WINAPI d3drm_texture3_GetShades(IDirect3DRMTexture3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static DWORD WINAPI d3drm_texture3_GetColors(IDirect3DRMTexture3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static DWORD WINAPI d3drm_texture3_GetDecalScale(IDirect3DRMTexture3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static BOOL WINAPI d3drm_texture3_GetDecalTransparency(IDirect3DRMTexture3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return FALSE;
+}
+
+static D3DCOLOR WINAPI d3drm_texture3_GetDecalTransparentColor(IDirect3DRMTexture3 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_texture3_InitFromImage(IDirect3DRMTexture3 *iface, D3DRMIMAGE *image)
+{
+    FIXME("iface %p, image %p stub!\n", iface, image);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_InitFromResource2(IDirect3DRMTexture3 *iface,
+        HMODULE module, const char *name, const char *type)
+{
+    FIXME("iface %p, module %p, name %s, type %s stub!\n",
+            iface, module, debugstr_a(name), debugstr_a(type));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_GenerateMIPMap(IDirect3DRMTexture3 *iface, DWORD flags)
+{
+    FIXME("iface %p, flags %#x stub!\n", iface, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_GetSurface(IDirect3DRMTexture3 *iface,
+        DWORD flags, IDirectDrawSurface **surface)
+{
+    FIXME("iface %p, flags %#x, surface %p stub!\n", iface, flags, surface);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetCacheOptions(IDirect3DRMTexture3 *iface, LONG importance, DWORD flags)
+{
+    FIXME("iface %p, importance %d, flags %#x stub!\n", iface, importance, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_GetCacheOptions(IDirect3DRMTexture3 *iface,
+        LONG *importance, DWORD *flags)
+{
+    FIXME("iface %p, importance %p, flags %p stub!\n", iface, importance, flags);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetDownsampleCallback(IDirect3DRMTexture3 *iface,
+        D3DRMDOWNSAMPLECALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_texture3_SetValidationCallback(IDirect3DRMTexture3 *iface,
+        D3DRMVALIDATIONCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMTexture3Vtbl d3drm_texture3_vtbl =
+{
+    d3drm_texture3_QueryInterface,
+    d3drm_texture3_AddRef,
+    d3drm_texture3_Release,
+    d3drm_texture3_Clone,
+    d3drm_texture3_AddDestroyCallback,
+    d3drm_texture3_DeleteDestroyCallback,
+    d3drm_texture3_SetAppData,
+    d3drm_texture3_GetAppData,
+    d3drm_texture3_SetName,
+    d3drm_texture3_GetName,
+    d3drm_texture3_GetClassName,
+    d3drm_texture3_InitFromFile,
+    d3drm_texture3_InitFromSurface,
+    d3drm_texture3_InitFromResource,
+    d3drm_texture3_Changed,
+    d3drm_texture3_SetColors,
+    d3drm_texture3_SetShades,
+    d3drm_texture3_SetDecalSize,
+    d3drm_texture3_SetDecalOrigin,
+    d3drm_texture3_SetDecalScale,
+    d3drm_texture3_SetDecalTransparency,
+    d3drm_texture3_SetDecalTransparentColor,
+    d3drm_texture3_GetDecalSize,
+    d3drm_texture3_GetDecalOrigin,
+    d3drm_texture3_GetImage,
+    d3drm_texture3_GetShades,
+    d3drm_texture3_GetColors,
+    d3drm_texture3_GetDecalScale,
+    d3drm_texture3_GetDecalTransparency,
+    d3drm_texture3_GetDecalTransparentColor,
+    d3drm_texture3_InitFromImage,
+    d3drm_texture3_InitFromResource2,
+    d3drm_texture3_GenerateMIPMap,
+    d3drm_texture3_GetSurface,
+    d3drm_texture3_SetCacheOptions,
+    d3drm_texture3_GetCacheOptions,
+    d3drm_texture3_SetDownsampleCallback,
+    d3drm_texture3_SetValidationCallback,
+};
+
+HRESULT Direct3DRMTexture_create(REFIID riid, IUnknown **out)
+{
+    struct d3drm_texture *object;
+
+    TRACE("riid %s, out %p.\n", debugstr_guid(riid), out);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMTexture2_iface.lpVtbl = &d3drm_texture2_vtbl;
+    object->IDirect3DRMTexture3_iface.lpVtbl = &d3drm_texture3_vtbl;
+    object->ref = 1;
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMTexture3))
+        *out = (IUnknown *)&object->IDirect3DRMTexture3_iface;
+    else
+        *out = (IUnknown *)&object->IDirect3DRMTexture2_iface;
+
+    return S_OK;
+}
diff --git a/reactos/dll/directx/wine/d3drm/version.rc b/reactos/dll/directx/wine/d3drm/version.rc
new file mode 100644 (file)
index 0000000..a9ce437
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2004 Ivan Leo Puoti
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WINE_FILEDESCRIPTION_STR "Wine Direct3D Retained Mode Utility Functions"
+#define WINE_FILENAME_STR "d3drm.dll"
+#define WINE_FILEVERSION 5,0,2134,14
+#define WINE_FILEVERSION_STR "5.0.2134.14"
+#define WINE_PRODUCTVERSION 5,0,2134,14
+#define WINE_PRODUCTVERSION_STR "5.0"
+
+#include "wine/wine_common_ver.rc"
diff --git a/reactos/dll/directx/wine/d3drm/viewport.c b/reactos/dll/directx/wine/d3drm/viewport.c
new file mode 100644 (file)
index 0000000..d8bfaa7
--- /dev/null
@@ -0,0 +1,824 @@
+/*
+ * Implementation of IDirect3DRMViewport Interface
+ *
+ * Copyright 2012 André Hentschel
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "d3drm_private.h"
+
+struct d3drm_viewport
+{
+    IDirect3DRMViewport IDirect3DRMViewport_iface;
+    IDirect3DRMViewport2 IDirect3DRMViewport2_iface;
+    LONG ref;
+    D3DVALUE back;
+    D3DVALUE front;
+    D3DVALUE field;
+    D3DRMPROJECTIONTYPE projection;
+};
+
+static inline struct d3drm_viewport *impl_from_IDirect3DRMViewport(IDirect3DRMViewport *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_viewport, IDirect3DRMViewport_iface);
+}
+
+static inline struct d3drm_viewport *impl_from_IDirect3DRMViewport2(IDirect3DRMViewport2 *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3drm_viewport, IDirect3DRMViewport2_iface);
+}
+
+static HRESULT WINAPI d3drm_viewport1_QueryInterface(IDirect3DRMViewport *iface, REFIID riid, void **out)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMViewport)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *out = &viewport->IDirect3DRMViewport_iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IDirect3DRMViewport2))
+    {
+        *out = &viewport->IDirect3DRMViewport2_iface;
+    }
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI d3drm_viewport1_AddRef(IDirect3DRMViewport *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+    ULONG refcount = InterlockedIncrement(&viewport->ref);
+
+    TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI d3drm_viewport1_Release(IDirect3DRMViewport *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+    ULONG refcount = InterlockedDecrement(&viewport->ref);
+
+    TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+    if (!refcount)
+        HeapFree(GetProcessHeap(), 0, viewport);
+
+    return refcount;
+}
+
+static HRESULT WINAPI d3drm_viewport1_Clone(IDirect3DRMViewport *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_AddDestroyCallback(IDirect3DRMViewport *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_DeleteDestroyCallback(IDirect3DRMViewport *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetAppData(IDirect3DRMViewport *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_viewport1_GetAppData(IDirect3DRMViewport *iface)
+{
+    FIXME("iface %p.\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetName(IDirect3DRMViewport *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_GetName(IDirect3DRMViewport *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_GetClassName(IDirect3DRMViewport *iface, DWORD *size, char *name)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    return IDirect3DRMViewport2_GetClassName(&viewport->IDirect3DRMViewport2_iface, size, name);
+}
+
+static HRESULT WINAPI d3drm_viewport1_Init(IDirect3DRMViewport *iface, IDirect3DRMDevice *device,
+        IDirect3DRMFrame *camera, DWORD x, DWORD y, DWORD width, DWORD height)
+{
+    FIXME("iface %p, device %p, camera %p, x %u, y %u, width %u, height %u stub!\n",
+            iface, device, camera, x, y, width, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_Clear(IDirect3DRMViewport *iface)
+{
+    FIXME("iface %p.\n", iface);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport1_Render(IDirect3DRMViewport *iface, IDirect3DRMFrame *frame)
+{
+    FIXME("iface %p, frame %p stub!\n", iface, frame);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetFront(IDirect3DRMViewport *iface, D3DVALUE front)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p, front %.8e.\n", iface, front);
+
+    return IDirect3DRMViewport2_SetFront(&viewport->IDirect3DRMViewport2_iface, front);
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetBack(IDirect3DRMViewport *iface, D3DVALUE back)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p, back %.8e.\n", iface, back);
+
+    return IDirect3DRMViewport2_SetBack(&viewport->IDirect3DRMViewport2_iface, back);
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetField(IDirect3DRMViewport *iface, D3DVALUE field)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p, field %.8e.\n", iface, field);
+
+    return IDirect3DRMViewport2_SetField(&viewport->IDirect3DRMViewport2_iface, field);
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetUniformScaling(IDirect3DRMViewport *iface, BOOL b)
+{
+    FIXME("iface %p, b %#x stub!\n", iface, b);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetCamera(IDirect3DRMViewport *iface, IDirect3DRMFrame *camera)
+{
+    FIXME("iface %p, camera %p stub!\n", iface, camera);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetProjection(IDirect3DRMViewport *iface, D3DRMPROJECTIONTYPE type)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p, type %#x.\n", iface, type);
+
+    return IDirect3DRMViewport2_SetProjection(&viewport->IDirect3DRMViewport2_iface, type);
+}
+
+static HRESULT WINAPI d3drm_viewport1_Transform(IDirect3DRMViewport *iface, D3DRMVECTOR4D *d, D3DVECTOR *s)
+{
+    FIXME("iface %p, d %p, s %p stub!\n", iface, d, s);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_InverseTransform(IDirect3DRMViewport *iface, D3DVECTOR *d, D3DRMVECTOR4D *s)
+{
+    FIXME("iface %p, d %p, s %p stub!\n", iface, d, s);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_Configure(IDirect3DRMViewport *iface,
+        LONG x, LONG y, DWORD width, DWORD height)
+{
+    FIXME("iface %p, x %d, y %d, width %u, height %u stub!\n", iface, x, y, width, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_ForceUpdate(IDirect3DRMViewport *iface,
+        DWORD x1, DWORD y1, DWORD x2, DWORD y2)
+{
+    FIXME("iface %p, x1 %u, y1 %u, x2 %u, y2 %u stub!\n", iface, x1, y1, x2, y2);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_SetPlane(IDirect3DRMViewport *iface,
+        D3DVALUE left, D3DVALUE right, D3DVALUE bottom, D3DVALUE top)
+{
+    FIXME("iface %p, left %.8e, right %.8e, bottom %.8e, top %.8e stub!\n",
+            iface, left, right, bottom, top);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_GetCamera(IDirect3DRMViewport *iface, IDirect3DRMFrame **camera)
+{
+    FIXME("iface %p, camera %p stub!\n", iface, camera);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_GetDevice(IDirect3DRMViewport *iface, IDirect3DRMDevice **device)
+{
+    FIXME("iface %p, device %p stub!\n", iface, device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_GetPlane(IDirect3DRMViewport *iface,
+        D3DVALUE *left, D3DVALUE *right, D3DVALUE *bottom, D3DVALUE *top)
+{
+    FIXME("iface %p, left %p, right %p, bottom %p, top %p stub!\n",
+            iface, left, right, bottom, top);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport1_Pick(IDirect3DRMViewport *iface,
+        LONG x, LONG y, IDirect3DRMPickedArray **visuals)
+{
+    FIXME("iface %p, x %d, y %d, visuals %p stub!\n", iface, x, y, visuals);
+
+    return E_NOTIMPL;
+}
+
+static BOOL WINAPI d3drm_viewport1_GetUniformScaling(IDirect3DRMViewport *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static LONG WINAPI d3drm_viewport1_GetX(IDirect3DRMViewport *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static LONG WINAPI d3drm_viewport1_GetY(IDirect3DRMViewport *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_viewport1_GetWidth(IDirect3DRMViewport *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_viewport1_GetHeight(IDirect3DRMViewport *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static D3DVALUE WINAPI d3drm_viewport1_GetField(IDirect3DRMViewport *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMViewport2_GetField(&viewport->IDirect3DRMViewport2_iface);
+}
+
+static D3DVALUE WINAPI d3drm_viewport1_GetBack(IDirect3DRMViewport *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMViewport2_GetBack(&viewport->IDirect3DRMViewport2_iface);
+}
+
+static D3DVALUE WINAPI d3drm_viewport1_GetFront(IDirect3DRMViewport *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMViewport2_GetFront(&viewport->IDirect3DRMViewport2_iface);
+}
+
+static D3DRMPROJECTIONTYPE WINAPI d3drm_viewport1_GetProjection(IDirect3DRMViewport *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return IDirect3DRMViewport2_GetProjection(&viewport->IDirect3DRMViewport2_iface);
+}
+
+static HRESULT WINAPI d3drm_viewport1_GetDirect3DViewport(IDirect3DRMViewport *iface,
+        IDirect3DViewport **viewport)
+{
+    FIXME("iface %p, viewport %p stub!\n", iface, viewport);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMViewportVtbl d3drm_viewport1_vtbl =
+{
+    d3drm_viewport1_QueryInterface,
+    d3drm_viewport1_AddRef,
+    d3drm_viewport1_Release,
+    d3drm_viewport1_Clone,
+    d3drm_viewport1_AddDestroyCallback,
+    d3drm_viewport1_DeleteDestroyCallback,
+    d3drm_viewport1_SetAppData,
+    d3drm_viewport1_GetAppData,
+    d3drm_viewport1_SetName,
+    d3drm_viewport1_GetName,
+    d3drm_viewport1_GetClassName,
+    d3drm_viewport1_Init,
+    d3drm_viewport1_Clear,
+    d3drm_viewport1_Render,
+    d3drm_viewport1_SetFront,
+    d3drm_viewport1_SetBack,
+    d3drm_viewport1_SetField,
+    d3drm_viewport1_SetUniformScaling,
+    d3drm_viewport1_SetCamera,
+    d3drm_viewport1_SetProjection,
+    d3drm_viewport1_Transform,
+    d3drm_viewport1_InverseTransform,
+    d3drm_viewport1_Configure,
+    d3drm_viewport1_ForceUpdate,
+    d3drm_viewport1_SetPlane,
+    d3drm_viewport1_GetCamera,
+    d3drm_viewport1_GetDevice,
+    d3drm_viewport1_GetPlane,
+    d3drm_viewport1_Pick,
+    d3drm_viewport1_GetUniformScaling,
+    d3drm_viewport1_GetX,
+    d3drm_viewport1_GetY,
+    d3drm_viewport1_GetWidth,
+    d3drm_viewport1_GetHeight,
+    d3drm_viewport1_GetField,
+    d3drm_viewport1_GetBack,
+    d3drm_viewport1_GetFront,
+    d3drm_viewport1_GetProjection,
+    d3drm_viewport1_GetDirect3DViewport,
+};
+
+static HRESULT WINAPI d3drm_viewport2_QueryInterface(IDirect3DRMViewport2 *iface, REFIID riid, void **out)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
+
+    return d3drm_viewport1_QueryInterface(&viewport->IDirect3DRMViewport_iface, riid, out);
+}
+
+static ULONG WINAPI d3drm_viewport2_AddRef(IDirect3DRMViewport2 *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return d3drm_viewport1_AddRef(&viewport->IDirect3DRMViewport_iface);
+}
+
+static ULONG WINAPI d3drm_viewport2_Release(IDirect3DRMViewport2 *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return d3drm_viewport1_Release(&viewport->IDirect3DRMViewport_iface);
+}
+
+static HRESULT WINAPI d3drm_viewport2_Clone(IDirect3DRMViewport2 *iface,
+        IUnknown *outer, REFIID iid, void **out)
+{
+    FIXME("iface %p, outer %p, iid %s, out %p stub!\n", iface, outer, debugstr_guid(iid), out);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_AddDestroyCallback(IDirect3DRMViewport2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_DeleteDestroyCallback(IDirect3DRMViewport2 *iface,
+        D3DRMOBJECTCALLBACK cb, void *ctx)
+{
+    FIXME("iface %p, cb %p, ctx %p stub!\n", iface, cb, ctx);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetAppData(IDirect3DRMViewport2 *iface, DWORD data)
+{
+    FIXME("iface %p, data %#x stub!\n", iface, data);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_viewport2_GetAppData(IDirect3DRMViewport2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return 0;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetName(IDirect3DRMViewport2 *iface, const char *name)
+{
+    FIXME("iface %p, name %s stub!\n", iface, debugstr_a(name));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_GetName(IDirect3DRMViewport2 *iface, DWORD *size, char *name)
+{
+    FIXME("iface %p, size %p, name %p stub!\n", iface, size, name);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_GetClassName(IDirect3DRMViewport2 *iface, DWORD *size, char *name)
+{
+    TRACE("iface %p, size %p, name %p.\n", iface, size, name);
+
+    if (!size || *size < strlen("Viewport") || !name)
+        return E_INVALIDARG;
+
+    strcpy(name, "Viewport");
+    *size = sizeof("Viewport");
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport2_Init(IDirect3DRMViewport2 *iface, IDirect3DRMDevice3 *device,
+        IDirect3DRMFrame3 *camera, DWORD x, DWORD y, DWORD width, DWORD height)
+{
+    FIXME("iface %p, device %p, camera %p, x %u, y %u, width %u, height %u stub!\n",
+            iface, device, camera, x, y, width, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_Clear(IDirect3DRMViewport2 *iface, DWORD flags)
+{
+    FIXME("iface %p, flags %#x.\n", iface, flags);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport2_Render(IDirect3DRMViewport2 *iface, IDirect3DRMFrame3 *frame)
+{
+    FIXME("iface %p, frame %p stub!\n", iface, frame);
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetFront(IDirect3DRMViewport2 *iface, D3DVALUE front)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p, front %.8e.\n", iface, front);
+
+    viewport->front = front;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetBack(IDirect3DRMViewport2 *iface, D3DVALUE back)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p, back %.8e.\n", iface, back);
+
+    viewport->back = back;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetField(IDirect3DRMViewport2 *iface, D3DVALUE field)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p, field %.8e.\n", iface, field);
+
+    viewport->field = field;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetUniformScaling(IDirect3DRMViewport2 *iface, BOOL b)
+{
+    FIXME("iface %p, b %#x stub!\n", iface, b);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetCamera(IDirect3DRMViewport2 *iface, IDirect3DRMFrame3 *camera)
+{
+    FIXME("iface %p, camera %p stub!\n", iface, camera);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetProjection(IDirect3DRMViewport2 *iface, D3DRMPROJECTIONTYPE type)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p, type %#x.\n", iface, type);
+
+    viewport->projection = type;
+
+    return D3DRM_OK;
+}
+
+static HRESULT WINAPI d3drm_viewport2_Transform(IDirect3DRMViewport2 *iface, D3DRMVECTOR4D *d, D3DVECTOR *s)
+{
+    FIXME("iface %p, d %p, s %p stub!\n", iface, d, s);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_InverseTransform(IDirect3DRMViewport2 *iface, D3DVECTOR *d, D3DRMVECTOR4D *s)
+{
+    FIXME("iface %p, d %p, s %p stub!\n", iface, d, s);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_Configure(IDirect3DRMViewport2 *iface,
+        LONG x, LONG y, DWORD width, DWORD height)
+{
+    FIXME("iface %p, x %d, y %d, width %u, height %u stub!\n", iface, x, y, width, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_ForceUpdate(IDirect3DRMViewport2* iface,
+        DWORD x1, DWORD y1, DWORD x2, DWORD y2)
+{
+    FIXME("iface %p, x1 %u, y1 %u, x2 %u, y2 %u stub!\n", iface, x1, y1, x2, y2);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_SetPlane(IDirect3DRMViewport2 *iface,
+        D3DVALUE left, D3DVALUE right, D3DVALUE bottom, D3DVALUE top)
+{
+    FIXME("iface %p, left %.8e, right %.8e, bottom %.8e, top %.8e stub!\n",
+            iface, left, right, bottom, top);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_GetCamera(IDirect3DRMViewport2 *iface, IDirect3DRMFrame3 **camera)
+{
+    FIXME("iface %p, camera %p stub!\n", iface, camera);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_GetDevice(IDirect3DRMViewport2 *iface, IDirect3DRMDevice3 **device)
+{
+    FIXME("iface %p, device %p stub!\n", iface, device);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_GetPlane(IDirect3DRMViewport2 *iface,
+        D3DVALUE *left, D3DVALUE *right, D3DVALUE *bottom, D3DVALUE *top)
+{
+    FIXME("iface %p, left %p, right %p, bottom %p, top %p stub!\n",
+            iface, left, right, bottom, top);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_Pick(IDirect3DRMViewport2 *iface,
+        LONG x, LONG y, IDirect3DRMPickedArray **visuals)
+{
+    FIXME("iface %p, x %d, y %d, visuals %p stub!\n", iface, x, y, visuals);
+
+    return E_NOTIMPL;
+}
+
+static BOOL WINAPI d3drm_viewport2_GetUniformScaling(IDirect3DRMViewport2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static LONG WINAPI d3drm_viewport2_GetX(IDirect3DRMViewport2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static LONG WINAPI d3drm_viewport2_GetY(IDirect3DRMViewport2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_viewport2_GetWidth(IDirect3DRMViewport2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static DWORD WINAPI d3drm_viewport2_GetHeight(IDirect3DRMViewport2 *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+
+    return E_NOTIMPL;
+}
+
+static D3DVALUE WINAPI d3drm_viewport2_GetField(IDirect3DRMViewport2 *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return viewport->field;
+}
+
+static D3DVALUE WINAPI d3drm_viewport2_GetBack(IDirect3DRMViewport2 *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return viewport->back;
+}
+
+static D3DVALUE WINAPI d3drm_viewport2_GetFront(IDirect3DRMViewport2 *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return viewport->front;
+}
+
+static D3DRMPROJECTIONTYPE WINAPI d3drm_viewport2_GetProjection(IDirect3DRMViewport2 *iface)
+{
+    struct d3drm_viewport *viewport = impl_from_IDirect3DRMViewport2(iface);
+
+    TRACE("iface %p.\n", iface);
+
+    return viewport->projection;
+}
+
+static HRESULT WINAPI d3drm_viewport2_GetDirect3DViewport(IDirect3DRMViewport2 *iface,
+        IDirect3DViewport **viewport)
+{
+    FIXME("iface %p, viewport %p stub!\n", iface, viewport);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_TransformVectors(IDirect3DRMViewport2 *iface,
+        DWORD vector_count, D3DRMVECTOR4D *dst, D3DVECTOR *src)
+{
+    FIXME("iface %p, vector_count %u, dst %p, src %p stub!\n", iface, vector_count, dst, src);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI d3drm_viewport2_InverseTransformVectors(IDirect3DRMViewport2 *iface,
+        DWORD vector_count, D3DVECTOR *dst, D3DRMVECTOR4D *src)
+{
+    FIXME("iface %p, vector_count %u, dst %p, src %p stub!\n", iface, vector_count, dst, src);
+
+    return E_NOTIMPL;
+}
+
+static const struct IDirect3DRMViewport2Vtbl d3drm_viewport2_vtbl =
+{
+    d3drm_viewport2_QueryInterface,
+    d3drm_viewport2_AddRef,
+    d3drm_viewport2_Release,
+    d3drm_viewport2_Clone,
+    d3drm_viewport2_AddDestroyCallback,
+    d3drm_viewport2_DeleteDestroyCallback,
+    d3drm_viewport2_SetAppData,
+    d3drm_viewport2_GetAppData,
+    d3drm_viewport2_SetName,
+    d3drm_viewport2_GetName,
+    d3drm_viewport2_GetClassName,
+    d3drm_viewport2_Init,
+    d3drm_viewport2_Clear,
+    d3drm_viewport2_Render,
+    d3drm_viewport2_SetFront,
+    d3drm_viewport2_SetBack,
+    d3drm_viewport2_SetField,
+    d3drm_viewport2_SetUniformScaling,
+    d3drm_viewport2_SetCamera,
+    d3drm_viewport2_SetProjection,
+    d3drm_viewport2_Transform,
+    d3drm_viewport2_InverseTransform,
+    d3drm_viewport2_Configure,
+    d3drm_viewport2_ForceUpdate,
+    d3drm_viewport2_SetPlane,
+    d3drm_viewport2_GetCamera,
+    d3drm_viewport2_GetDevice,
+    d3drm_viewport2_GetPlane,
+    d3drm_viewport2_Pick,
+    d3drm_viewport2_GetUniformScaling,
+    d3drm_viewport2_GetX,
+    d3drm_viewport2_GetY,
+    d3drm_viewport2_GetWidth,
+    d3drm_viewport2_GetHeight,
+    d3drm_viewport2_GetField,
+    d3drm_viewport2_GetBack,
+    d3drm_viewport2_GetFront,
+    d3drm_viewport2_GetProjection,
+    d3drm_viewport2_GetDirect3DViewport,
+    d3drm_viewport2_TransformVectors,
+    d3drm_viewport2_InverseTransformVectors,
+};
+
+HRESULT Direct3DRMViewport_create(REFIID riid, IUnknown **out)
+{
+    struct d3drm_viewport *object;
+
+    TRACE("riid %s, out %p.\n", debugstr_guid(riid), out);
+
+    if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IDirect3DRMViewport_iface.lpVtbl = &d3drm_viewport1_vtbl;
+    object->IDirect3DRMViewport2_iface.lpVtbl = &d3drm_viewport2_vtbl;
+    object->ref = 1;
+
+    if (IsEqualGUID(riid, &IID_IDirect3DRMViewport2))
+        *out = (IUnknown *)&object->IDirect3DRMViewport2_iface;
+    else
+        *out = (IUnknown *)&object->IDirect3DRMViewport_iface;
+
+    return S_OK;
+}
index 27440e1..0934e6a 100644 (file)
@@ -31,6 +31,7 @@ reactos/dll/directx/wine/amstream       # Synced to Wine-1.7.27
 reactos/dll/directx/wine/d3d8           # Synced to Wine-1.7.27
 reactos/dll/directx/wine/d3d9           # Synced to Wine-1.7.27
 reactos/dll/directx/wine/d3dcompiler_43 # Synced to Wine-1.7.27
+reactos/dll/directx/wine/d3drm          # Synced to Wine-1.7.27
 reactos/dll/directx/wine/d3dx9_24 => 43 # Synced to Wine-1.7.27
 reactos/dll/directx/wine/d3dxof         # Synced to Wine-1.7.27
 reactos/dll/directx/wine/ddraw          # Synced to Wine-1.7.27