This feature is incredibly useful, but I would think it would be better managed in the core; especially as moving to x64 breaks the landing detection. This would also allow addons that rely on this feature to work with any graphics plugin.
Also, potential procedural fill-ins for non-existing or microterrain could be handled by the client as well, which has the potential advantage of leveraging the power of the GPU for such tasks.I think the former is better, because that way things like super-sampling of tiles is in the command of the OVP client, making dissonance between visual and collision engine a thing of the past.
# HG changeset patch
# User face <[email protected]>
# Date 1627829270 -7200
# Sun Aug 01 16:47:50 2021 +0200
# Node ID e6873b5d96eecda521cd327f92ce289e25a82567
# Parent d2ac1f83f3961a25ad0ff4c2ec05b5c516955c0a
Flattening: exchanging hooking with API usage
diff --git a/Orbitersdk/D3D9Client/D3D9Client.cpp b/Orbitersdk/D3D9Client/D3D9Client.cpp
--- a/Orbitersdk/D3D9Client/D3D9Client.cpp
+++ b/Orbitersdk/D3D9Client/D3D9Client.cpp
@@ -231,9 +231,6 @@
}
};
-DWORD g_Hook;
-void *g_HookPoint = (void *)0x4185fc;
-void *g_TrampolineReturn = (void *)0x418604;
std::unordered_map<OBJHANDLE, std::unordered_map<int, std::unordered_map<int, std::unordered_map<int, std::vector<FlatShape*>>>>> g_ElevationFlatteningShapes;
std::unordered_map<OBJHANDLE, std::vector<FlatShape*>> g_ShapeStore;
std::unordered_map<OBJHANDLE, bool> g_ShapesLoaded;
@@ -385,24 +382,8 @@
g_ShapesLoaded[hPlanet] = true;
}
-//The following array is:
-//_asm
-//{
-// fld qword [ebp+0x8] // load floating point (lat or lng)
-// fld qword [ebp+0x10] // load floating point (lng or lat)
-// fxch st1 // swap FPU storage
-//}
-byte g_Original[8] = { 0xdd, 0x45, 0x08, 0xdd, 0x45, 0x10, 0xd9, 0xc9 };
-
-//The following array is:
-//_asm
-//{
-// jmp dword ptr [HOOKFUNCTION]; //jump to dynamically detected address
-//}
-byte g_Code[8] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
template <typename Type>
-bool FilterElevation(OBJHANDLE hPlanet, int lvl, int ilat, int ilng, Type *elev)
+bool FilterElevation(OBJHANDLE hPlanet, int lvl, int ilat, int ilng, double elev_res, Type *elev)
{
if (!elev) return false;
if (g_ShapesLoaded.find(hPlanet) == g_ShapesLoaded.end()) ProcessPlanetFlats(hPlanet);
@@ -436,7 +417,7 @@
if (dist <= 1.0)
{
// Do the math in INT16 basis even for "float" output
- INT16 elevation = INT16(shape->Height);
+ INT16 elevation = INT16((double)shape->Height / elev_res);
if (shape->Falloff > 0)
{
for (auto pot = 0; pot < shape->Type; pot++)
@@ -446,7 +427,7 @@
if (dist >= 1 - shape->Falloff)
{
double alpha = (dist - 1 + shape->Falloff) / shape->Falloff;
- elevation = INT16(elev[i] * alpha + shape->Height * (1 - alpha));
+ elevation = INT16(elev[i] * alpha + (double)shape->Height / elev_res * (1 - alpha));
}
}
// Convert to float or keep as an INT16 depending on case
@@ -458,13 +439,15 @@
}
-void FilterElevationPhysics(OBJHANDLE hPlanet, int lvl, int ilat, int ilng, INT16 *elev)
+bool FilterElevationPhysics(OBJHANDLE hPlanet, int lvl, int ilat, int ilng, double elev_res, INT16 *elev)
{
- if (!Config->bFlatsEnabled) return;
+ if (!Config->bFlatsEnabled) return false;
char name[64];
- oapiGetObjectName(hPlanet, name, 64);
- if (FilterElevation<INT16>(hPlanet, lvl, ilat, ilng, elev))
- LogClr("Coral", "FilterElevation[Physics][%s]: Level=%d, ilat=%d, ilng=%d", name, lvl, ilat, ilng);
+ oapiGetObjectName(hPlanet, name, 64);
+ auto result = FilterElevation<INT16>(hPlanet, lvl, ilat, ilng, elev_res, elev);
+ if (result)
+ LogClr("Coral", "FilterElevation[Physics][%s]: Level=%d, ilat=%d, ilng=%d", name, lvl, ilat, ilng);
+ return result;
}
@@ -473,69 +456,10 @@
if (!Config->bFlatsEnabled) return;
char name[64];
oapiGetObjectName(hPlanet, name, 64);
- if (FilterElevation<float>(hPlanet, lvl, ilat, ilng, elev))
+ if (FilterElevation<float>(hPlanet, lvl, ilat, ilng, 1.0, elev))
LogClr("Coral", "FilterElevation[Graphics][%s]: Level=%d, ilat=%d, ilng=%d", name, lvl, ilat, ilng);
}
-void Trampoline()
-{
- //__asm
- //{
- // pop ebp // that's necessary because the compiler saved the pointer to the stack
- // mov eax, dword ptr[edi] // elev
- // mov ecx, dword ptr[esp + 0x54] // ilng
- // mov edx, dword ptr[esp + 0x2c] // ilat
- // push eax // arg4 = elev
- // mov eax, dword ptr[esp + 0x40] // internal GBody pointer
- // mov eax, dword ptr[eax] // OBJHANDLE
- // push ecx // arg3 = ilng
- // push edx // arg2 = ilat
- // push esi // arg1 = lvl
- // push eax // arg0 = OBJHANDLE
- // call FilterElevationPhysics // filter function call
- // add esp, 14h // 5 arguments = 5*2 bytes = 20dec = 14h
- // fld qword ptr[ebp + 0x8] // start of overwritten bytes in original position
- // fld qword ptr[ebp + 0x10]
- // fxch
- // jmp g_TrampolineReturn // return from trampoline to original function
- //}
-}
-
-int WriteCode(void *address, void *code, DWORD len)
-{
- //Get process information
- HANDLE hSelf = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION, FALSE, ::GetCurrentProcessId());
- if (hSelf == NULL) return -1;
- MEMORY_BASIC_INFORMATION mbi;
-
- //Open up page of linked address
- if (VirtualQueryEx(hSelf, (LPVOID)address, &mbi, sizeof(mbi)) != sizeof(mbi)) return -2;
- PVOID pvRgnBaseAddress = mbi.BaseAddress;
- DWORD dwOldProtect1, dwOldProtect2, dwFake;
- if (!::VirtualProtectEx(hSelf, pvRgnBaseAddress, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect1)) return -3;
- BOOL bStridePage = FALSE;
- LPBYTE lpByte = (LPBYTE)pvRgnBaseAddress;
- lpByte += 4096;
- if ((DWORD)lpByte < (DWORD)address + 4) bStridePage = TRUE;
- PVOID pvRgnBaseAddress2 = (LPVOID)lpByte;
- if (bStridePage)
- if (!::VirtualProtectEx(hSelf, pvRgnBaseAddress2, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect2))
- {
- ::VirtualProtectEx(hSelf, pvRgnBaseAddress, 4, dwOldProtect1, &dwFake);
- return -4;
- }
-
- //Write code
- memcpy(address, code, len);
-
- //Lock again
- ::VirtualProtectEx(hSelf, pvRgnBaseAddress, 4, dwOldProtect1, &dwFake);
- if (bStridePage) ::VirtualProtectEx(hSelf, pvRgnBaseAddress2, 4, dwOldProtect2, &dwFake);
-
- return 0;
-}
-
-
@@ -588,25 +512,7 @@
LabelPos (0)
{
- // =====================================================================
- // Face's terrain flattening
- // Hook up collision loader in core Orbiter
- // Hooks are placed recardless of "Enable Terrain Flattening", simplier that way
- // =====================================================================
- union
- {
- void *pointer;
- byte bytes[4];
- DWORD value;
- } p;
-
- g_Hook = (DWORD)(void *)Trampoline;
- p.pointer = (void *)&g_Hook;
- if (memcmp((void *)g_Original, g_HookPoint, 8) == 0)
- {
- for (int i = 0; i < 4; i++) g_Code[2 + i] = p.bytes[i];
- WriteCode(g_HookPoint, (void *)g_Code, 8);
- }
+
}
// ==============================================================
@@ -616,9 +522,6 @@
LogAlw("D3D9Client destructor called");
SAFE_DELETE(vtab);
- //Unhook
- WriteCode(g_HookPoint, (void *)g_Original, 8);
-
// Free constellation names memory (if allocted)
if (g_cm_list) {
for (DWORD n = 0; n < g_cm_list_count; ++n) {
@@ -2948,6 +2851,14 @@
return;
}
SURFACE(surf)->ReleaseDC(hDC);
+}
+
+// =======================================================================
+
+bool D3D9Client::clbkFilterElevation(OBJHANDLE hPlanet, int ilat, int ilng, int lvl, double elev_res, INT16* elev)
+{
+ _TRACE;
+ return FilterElevationPhysics(hPlanet, lvl, ilat, ilng, elev_res, elev);
}
// =======================================================================
diff --git a/Orbitersdk/D3D9Client/D3D9Client.h b/Orbitersdk/D3D9Client/D3D9Client.h
--- a/Orbitersdk/D3D9Client/D3D9Client.h
+++ b/Orbitersdk/D3D9Client/D3D9Client.h
@@ -985,6 +985,23 @@
* \todo This method should be moved into the GDIClient class
*/
void clbkReleaseSurfaceDC (SURFHANDLE surf, HDC hDC);
+ // @}
+
+ /**
+ * \brief Filter elevation grid data
+ * \param hPlanet object handle of the planet the data belongs to
+ * \param ilat patch latitude index
+ * \param ilng patch longitude index
+ * \param lvl patch resolution level
+ * \param elev_res elevation level resolution
+ * \param elev pointer to array with elevation grid data
+ * \default None.
+ * \note Clients that manipulate elevation file data in memory (e.g. for flattening
+ * features) for visuals should overload this method in order to manipulate the
+ * terrain collision data in the same way. As soon as the internal collision tile
+ * is loaded in the core, the callback is invoked.
+ */
+ virtual bool clbkFilterElevation(OBJHANDLE hPlanet, int ilat, int ilng, int lvl, double elev_res, INT16* elev);
// @}
# HG changeset patch
# User face <[email protected]>
# Date 1627829270 -7200
# Sun Aug 01 16:47:50 2021 +0200
# Node ID e6873b5d96eecda521cd327f92ce289e25a82567
# Parent d2ac1f83f3961a25ad0ff4c2ec05b5c516955c0a
Flattening: exchanging hooking with API usage
diff --git a/Orbitersdk/D3D9Client/D3D9Client.cpp b/Orbitersdk/D3D9Client/D3D9Client.cpp
--- a/Orbitersdk/D3D9Client/D3D9Client.cpp
+++ b/Orbitersdk/D3D9Client/D3D9Client.cpp
@@ -231,9 +231,6 @@
}
};
-DWORD g_Hook;
-void *g_HookPoint = (void *)0x4185fc;
-void *g_TrampolineReturn = (void *)0x418604;
std::unordered_map<OBJHANDLE, std::unordered_map<int, std::unordered_map<int, std::unordered_map<int, std::vector<FlatShape*>>>>> g_ElevationFlatteningShapes;
std::unordered_map<OBJHANDLE, std::vector<FlatShape*>> g_ShapeStore;
std::unordered_map<OBJHANDLE, bool> g_ShapesLoaded;
@@ -385,24 +382,8 @@
g_ShapesLoaded[hPlanet] = true;
}
-//The following array is:
-//_asm
-//{
-// fld qword [ebp+0x8] // load floating point (lat or lng)
-// fld qword [ebp+0x10] // load floating point (lng or lat)
-// fxch st1 // swap FPU storage
-//}
-byte g_Original[8] = { 0xdd, 0x45, 0x08, 0xdd, 0x45, 0x10, 0xd9, 0xc9 };
-
-//The following array is:
-//_asm
-//{
-// jmp dword ptr [HOOKFUNCTION]; //jump to dynamically detected address
-//}
-byte g_Code[8] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
template <typename Type>
-bool FilterElevation(OBJHANDLE hPlanet, int lvl, int ilat, int ilng, Type *elev)
+bool FilterElevation(OBJHANDLE hPlanet, int lvl, int ilat, int ilng, double elev_res, Type *elev)
{
if (!elev) return false;
if (g_ShapesLoaded.find(hPlanet) == g_ShapesLoaded.end()) ProcessPlanetFlats(hPlanet);
@@ -436,7 +417,7 @@
if (dist <= 1.0)
{
// Do the math in INT16 basis even for "float" output
- INT16 elevation = INT16(shape->Height);
+ INT16 elevation = INT16((double)shape->Height / elev_res);
if (shape->Falloff > 0)
{
for (auto pot = 0; pot < shape->Type; pot++)
@@ -446,7 +427,7 @@
if (dist >= 1 - shape->Falloff)
{
double alpha = (dist - 1 + shape->Falloff) / shape->Falloff;
- elevation = INT16(elev[i] * alpha + shape->Height * (1 - alpha));
+ elevation = INT16(elev[i] * alpha + (double)shape->Height / elev_res * (1 - alpha));
}
}
// Convert to float or keep as an INT16 depending on case
@@ -458,13 +439,15 @@
}
-void FilterElevationPhysics(OBJHANDLE hPlanet, int lvl, int ilat, int ilng, INT16 *elev)
+bool FilterElevationPhysics(OBJHANDLE hPlanet, int lvl, int ilat, int ilng, double elev_res, INT16 *elev)
{
- if (!Config->bFlatsEnabled) return;
+ if (!Config->bFlatsEnabled) return false;
char name[64];
- oapiGetObjectName(hPlanet, name, 64);
- if (FilterElevation<INT16>(hPlanet, lvl, ilat, ilng, elev))
- LogClr("Coral", "FilterElevation[Physics][%s]: Level=%d, ilat=%d, ilng=%d", name, lvl, ilat, ilng);
+ oapiGetObjectName(hPlanet, name, 64);
+ auto result = FilterElevation<INT16>(hPlanet, lvl, ilat, ilng, elev_res, elev);
+ if (result)
+ LogClr("Coral", "FilterElevation[Physics][%s]: Level=%d, ilat=%d, ilng=%d", name, lvl, ilat, ilng);
+ return result;
}
@@ -473,69 +456,10 @@
if (!Config->bFlatsEnabled) return;
char name[64];
oapiGetObjectName(hPlanet, name, 64);
- if (FilterElevation<float>(hPlanet, lvl, ilat, ilng, elev))
+ if (FilterElevation<float>(hPlanet, lvl, ilat, ilng, 1.0, elev))
LogClr("Coral", "FilterElevation[Graphics][%s]: Level=%d, ilat=%d, ilng=%d", name, lvl, ilat, ilng);
}
-void Trampoline()
-{
- //__asm
- //{
- // pop ebp // that's necessary because the compiler saved the pointer to the stack
- // mov eax, dword ptr[edi] // elev
- // mov ecx, dword ptr[esp + 0x54] // ilng
- // mov edx, dword ptr[esp + 0x2c] // ilat
- // push eax // arg4 = elev
- // mov eax, dword ptr[esp + 0x40] // internal GBody pointer
- // mov eax, dword ptr[eax] // OBJHANDLE
- // push ecx // arg3 = ilng
- // push edx // arg2 = ilat
- // push esi // arg1 = lvl
- // push eax // arg0 = OBJHANDLE
- // call FilterElevationPhysics // filter function call
- // add esp, 14h // 5 arguments = 5*2 bytes = 20dec = 14h
- // fld qword ptr[ebp + 0x8] // start of overwritten bytes in original position
- // fld qword ptr[ebp + 0x10]
- // fxch
- // jmp g_TrampolineReturn // return from trampoline to original function
- //}
-}
-
-int WriteCode(void *address, void *code, DWORD len)
-{
- //Get process information
- HANDLE hSelf = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION, FALSE, ::GetCurrentProcessId());
- if (hSelf == NULL) return -1;
- MEMORY_BASIC_INFORMATION mbi;
-
- //Open up page of linked address
- if (VirtualQueryEx(hSelf, (LPVOID)address, &mbi, sizeof(mbi)) != sizeof(mbi)) return -2;
- PVOID pvRgnBaseAddress = mbi.BaseAddress;
- DWORD dwOldProtect1, dwOldProtect2, dwFake;
- if (!::VirtualProtectEx(hSelf, pvRgnBaseAddress, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect1)) return -3;
- BOOL bStridePage = FALSE;
- LPBYTE lpByte = (LPBYTE)pvRgnBaseAddress;
- lpByte += 4096;
- if ((DWORD)lpByte < (DWORD)address + 4) bStridePage = TRUE;
- PVOID pvRgnBaseAddress2 = (LPVOID)lpByte;
- if (bStridePage)
- if (!::VirtualProtectEx(hSelf, pvRgnBaseAddress2, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect2))
- {
- ::VirtualProtectEx(hSelf, pvRgnBaseAddress, 4, dwOldProtect1, &dwFake);
- return -4;
- }
-
- //Write code
- memcpy(address, code, len);
-
- //Lock again
- ::VirtualProtectEx(hSelf, pvRgnBaseAddress, 4, dwOldProtect1, &dwFake);
- if (bStridePage) ::VirtualProtectEx(hSelf, pvRgnBaseAddress2, 4, dwOldProtect2, &dwFake);
-
- return 0;
-}
-
-
@@ -588,25 +512,7 @@
LabelPos (0)
{
- // =====================================================================
- // Face's terrain flattening
- // Hook up collision loader in core Orbiter
- // Hooks are placed recardless of "Enable Terrain Flattening", simplier that way
- // =====================================================================
- union
- {
- void *pointer;
- byte bytes[4];
- DWORD value;
- } p;
-
- g_Hook = (DWORD)(void *)Trampoline;
- p.pointer = (void *)&g_Hook;
- if (memcmp((void *)g_Original, g_HookPoint, 8) == 0)
- {
- for (int i = 0; i < 4; i++) g_Code[2 + i] = p.bytes[i];
- WriteCode(g_HookPoint, (void *)g_Code, 8);
- }
+
}
// ==============================================================
@@ -616,9 +522,6 @@
LogAlw("D3D9Client destructor called");
SAFE_DELETE(vtab);
- //Unhook
- WriteCode(g_HookPoint, (void *)g_Original, 8);
-
// Free constellation names memory (if allocted)
if (g_cm_list) {
for (DWORD n = 0; n < g_cm_list_count; ++n) {
@@ -2948,6 +2851,14 @@
return;
}
SURFACE(surf)->ReleaseDC(hDC);
+}
+
+// =======================================================================
+
+bool D3D9Client::clbkFilterElevation(OBJHANDLE hPlanet, int ilat, int ilng, int lvl, double elev_res, INT16* elev)
+{
+ _TRACE;
+ return FilterElevationPhysics(hPlanet, lvl, ilat, ilng, elev_res, elev);
}
// =======================================================================
diff --git a/Orbitersdk/D3D9Client/D3D9Client.h b/Orbitersdk/D3D9Client/D3D9Client.h
--- a/Orbitersdk/D3D9Client/D3D9Client.h
+++ b/Orbitersdk/D3D9Client/D3D9Client.h
@@ -985,6 +985,23 @@
* \todo This method should be moved into the GDIClient class
*/
void clbkReleaseSurfaceDC (SURFHANDLE surf, HDC hDC);
+ // @}
+
+ /**
+ * \brief Filter elevation grid data
+ * \param hPlanet object handle of the planet the data belongs to
+ * \param ilat patch latitude index
+ * \param ilng patch longitude index
+ * \param lvl patch resolution level
+ * \param elev_res elevation level resolution
+ * \param elev pointer to array with elevation grid data
+ * \default None.
+ * \note Clients that manipulate elevation file data in memory (e.g. for flattening
+ * features) for visuals should overload this method in order to manipulate the
+ * terrain collision data in the same way. As soon as the internal collision tile
+ * is loaded in the core, the callback is invoked.
+ */
+ virtual bool clbkFilterElevation(OBJHANDLE hPlanet, int ilat, int ilng, int lvl, double elev_res, INT16* elev);
// @}
Ok, Thanks. I will look into it. Right now I am trying to figure out the Git. After I got the Git repository up and running then maybe you can send a "pull request". And we get the code in.