port: CMapOutdoor + PythonBackground + minimap (1:1 40250)

GameLib map/area/terrain units, PRTerrainLib Terrain/TextureSet,
PythonBackground(+Module) and ColorTransitionHelper ported verbatim;
pending stand-ins and background module stubs removed. Hand edits:
BeginEnvironment's pointer tag via uintptr_t, LoadWaterMap reads the
file's 32-bit longs. Terrain draw passes stay platform no-ops (Godot
draws the terrain). RecordingDevice gains textures, buffers and render
targets; orthographic draws become UI commands so CPythonMiniMap's
masked tiles show through minimap_image_filter in python_ui_surface.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-24 03:50:09 +09:00
co-authored by Claude Opus 5.5
parent b69116992c
commit 2ead95756e
100 changed files with 17679 additions and 1514 deletions
+107
View File
@@ -0,0 +1,107 @@
// Platform implementation of EterBase/FileDir.h (40250 EterBase/FileDir.cpp): the 40250 code as is, over the
// FindFirstFile/FindNextFile/FindClose of common/Win32Crt.h.
#include "EterBase/StdAfx.h"
#include "EterBase/FileDir.h"
#include <string>
CDir::CDir()
{
Initialize();
}
CDir::~CDir()
{
Destroy();
}
void CDir::Destroy()
{
if (m_hFind)
FindClose(m_hFind);
Initialize();
}
bool CDir::Create(const char * c_szFilter, const char* c_szPath, BOOL bCheckedExtension)
{
Destroy();
std::string stPath = c_szPath;
if (stPath.length())
{
char end = stPath[stPath.length() - 1];
if (end != '\\')
stPath+='\\';
}
std::string stQuery;
stQuery += stPath;
stQuery += "*.*";
m_wfd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
m_hFind = FindFirstFile(stQuery.c_str(), &m_wfd);
if (m_hFind == INVALID_HANDLE_VALUE)
return true;
do
{
if (*m_wfd.cFileName == '.')
continue;
if (IsFolder())
{
if (!OnFolder(c_szFilter, stPath.c_str(), m_wfd.cFileName))
return false;
}
else
{
const char * c_szExtension = strchr(m_wfd.cFileName, '.');
if (!c_szExtension)
continue;
// NOTE : 임시 변수 - [levites]
// 최종적으로는 무조건 TRUE 형태로 만든다.
// 그전에 전 프로젝트의 CDir을 사용하는 곳에서 Extension을 "wav", "gr2" 이런식으로 넣게끔 한다. - [levites]
if (bCheckedExtension)
{
std::string strFilter = c_szFilter;
int iPos = strFilter.find_first_of(';', 0);
if (iPos > 0)
{
std::string strFirstFilter = std::string(c_szFilter).substr(0, iPos);
std::string strSecondFilter = std::string(c_szFilter).substr(iPos+1, strlen(c_szFilter));
if (0 != strFirstFilter.compare(c_szExtension+1) && 0 != strSecondFilter.compare(c_szExtension+1))
continue;
}
else
{
if (0 != stricmp(c_szExtension+1, c_szFilter))
continue;
}
}
if (!OnFile(stPath.c_str(), m_wfd.cFileName))
return false;
}
}
while (FindNextFile(m_hFind, &m_wfd));
return true;
}
bool CDir::IsFolder()
{
if (m_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return true;
return false;
}
void CDir::Initialize()
{
memset(&m_wfd, 0, sizeof(m_wfd));
m_hFind = NULL;
}
@@ -0,0 +1,23 @@
// Platform implementation of EterBase/TempFile.h (40250 EterBase/TempFile.cpp): the 40250 code as is; the file
// name comes from the platform CreateTempFileName and DeleteFile is the common/Win32Crt.h shim.
#include "EterBase/StdAfx.h"
#include "EterBase/TempFile.h"
#include "EterBase/Utils.h"
#include "EterBase/Debug.h"
CTempFile::~CTempFile()
{
Destroy();
DeleteFile(m_szFileName);
}
CTempFile::CTempFile(const char * c_pszPrefix)
{
strncpy(m_szFileName, CreateTempFileName(c_pszPrefix), MAX_PATH);
if (!Create(m_szFileName, CFileBase::FILEMODE_WRITE))
{
TraceError("CTempFile::CTempFile cannot create temporary file. (filename: %s)", m_szFileName);
return;
}
}
@@ -3,6 +3,8 @@
#include "UIRenderCommands.h"
#include "CpuBuffer.h"
#include <algorithm>
#include <cmath>
#include <cstring>
#include <mutex>
@@ -52,6 +54,148 @@ void copy_color(float out[4], const D3DCOLORVALUE& c)
out[0] = c.r; out[1] = c.g; out[2] = c.b; out[3] = c.a;
}
int format_bytes(D3DFORMAT format)
{
switch (format)
{
case D3DFMT_A4R4G4B4: case D3DFMT_R5G6B5: case D3DFMT_A1R5G5B5: case D3DFMT_X1R5G5B5: case D3DFMT_X4R4G4B4:
case D3DFMT_D16: case D3DFMT_D16_LOCKABLE:
return 2;
case D3DFMT_A8: case D3DFMT_L8:
return 1;
default:
return 4;
}
}
// PORT: device-created resources live in CPU memory with D3D reference counting. Textures made by
// CreateTexture (CTerrain's splat alpha maps and attribute marks, CSnowEnvironment's blur targets)
// keep their mip levels as bytes; nothing samples them because terrain and offscreen passes are
// drawn by the Godot side.
struct CpuTexture;
struct CpuSurface final : IDirect3DSurface8
{
ULONG refs = 1;
CpuTexture* parent = nullptr; // a texture level, or null for a standalone surface
UINT level = 0;
D3DSURFACE_DESC desc = {};
std::vector<uint8_t> bytes; // standalone surfaces only
ULONG AddRef() override { return ++refs; }
ULONG Release() override;
HRESULT GetDesc(D3DSURFACE_DESC* out) override { *out = desc; return S_OK; }
HRESULT LockRect(D3DLOCKED_RECT* locked, const RECT*, DWORD) override;
HRESULT UnlockRect() override { return S_OK; }
};
struct CpuTexture final : IDirect3DTexture8
{
struct Level { D3DSURFACE_DESC desc; std::vector<uint8_t> bytes; };
ULONG refs = 1;
std::vector<Level> levels;
ULONG AddRef() override { return ++refs; }
ULONG Release() override
{
const ULONG left = --refs;
if (!left)
delete this;
return left;
}
DWORD GetLevelCount() override { return DWORD(levels.size()); }
HRESULT GetLevelDesc(UINT level, D3DSURFACE_DESC* out) override
{
if (level >= levels.size())
return E_FAIL;
*out = levels[level].desc;
return S_OK;
}
HRESULT GetSurfaceLevel(UINT level, IDirect3DSurface8** out) override
{
if (level >= levels.size())
return E_FAIL;
auto* surface = new CpuSurface();
surface->parent = this;
surface->level = level;
surface->desc = levels[level].desc;
AddRef();
*out = surface;
return S_OK;
}
HRESULT LockRect(UINT level, D3DLOCKED_RECT* locked, const RECT*, DWORD) override
{
if (level >= levels.size())
return E_FAIL;
locked->Pitch = INT(levels[level].desc.Width * format_bytes(levels[level].desc.Format));
locked->pBits = levels[level].bytes.data();
return S_OK;
}
HRESULT UnlockRect(UINT level) override { return level < levels.size() ? S_OK : E_FAIL; }
};
ULONG CpuSurface::Release()
{
const ULONG left = --refs;
if (!left)
{
if (parent)
parent->Release();
delete this;
}
return left;
}
HRESULT CpuSurface::LockRect(D3DLOCKED_RECT* locked, const RECT* rect, DWORD flags)
{
if (parent)
return parent->LockRect(level, locked, rect, flags);
locked->Pitch = INT(desc.Width * format_bytes(desc.Format));
locked->pBits = bytes.data();
return S_OK;
}
D3DSURFACE_DESC surface_desc(UINT width, UINT height, D3DFORMAT format, DWORD usage, D3DPOOL pool)
{
D3DSURFACE_DESC desc = {};
desc.Format = format;
desc.Type = D3DRTYPE_SURFACE;
desc.Usage = usage;
desc.Pool = pool;
desc.Size = width * height * format_bytes(format);
desc.MultiSampleType = D3DMULTISAMPLE_NONE;
desc.Width = width;
desc.Height = height;
return desc;
}
struct DeviceVertexBuffer final : MtCpuVertexBuffer
{
ULONG refs = 1;
ULONG AddRef() override { return ++refs; }
ULONG Release() override
{
const ULONG left = --refs;
if (!left)
delete this;
return left;
}
};
struct DeviceIndexBuffer final : MtCpuIndexBuffer
{
ULONG refs = 1;
ULONG AddRef() override { return ++refs; }
ULONG Release() override
{
const ULONG left = --refs;
if (!left)
delete this;
return left;
}
};
class RecordingDevice final : public IDirect3DDevice8
{
public:
@@ -63,6 +207,23 @@ public:
std::memset(&m_material, 0, sizeof(m_material));
m_material.Diffuse = { 1, 1, 1, 1 };
std::memset(m_lights, 0, sizeof(m_lights));
auto* backBuffer = new CpuSurface();
backBuffer->desc = surface_desc(width, height, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT);
m_backBuffer = backBuffer;
auto* depthBuffer = new CpuSurface();
depthBuffer->desc = surface_desc(width, height, D3DFMT_D16, D3DUSAGE_DEPTHSTENCIL, D3DPOOL_DEFAULT);
m_depthBuffer = depthBuffer;
m_renderTarget = m_backBuffer;
m_renderTarget->AddRef();
m_depthStencil = m_depthBuffer;
m_depthStencil->AddRef();
}
~RecordingDevice() override
{
m_renderTarget->Release();
m_depthStencil->Release();
m_backBuffer->Release();
m_depthBuffer->Release();
}
ULONG AddRef() override { return ++m_refs; }
@@ -120,6 +281,84 @@ public:
m_lights[index] = *light;
return S_OK;
}
HRESULT LightEnable(DWORD index, BOOL enable) override
{
if (index < 8)
m_lightEnabled[index] = enable != FALSE;
return S_OK;
}
HRESULT CreateTexture(UINT width, UINT height, UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DTexture8** out) override
{
if (!width || !height)
return E_FAIL;
auto* texture = new CpuTexture();
// Levels == 0 builds the full chain down to 1x1.
for (UINT w = width, h = height; ; w = std::max(1u, w / 2), h = std::max(1u, h / 2))
{
CpuTexture::Level level;
level.desc = surface_desc(w, h, format, usage, pool);
level.bytes.resize(level.desc.Size);
texture->levels.push_back(std::move(level));
if ((levels && texture->levels.size() == levels) || (w == 1 && h == 1))
break;
}
*out = texture;
return S_OK;
}
HRESULT CreateVertexBuffer(UINT length, DWORD, DWORD fvf, D3DPOOL, IDirect3DVertexBuffer8** out) override
{
auto* buffer = new DeviceVertexBuffer();
buffer->bytes.resize(length);
buffer->fvf = fvf;
*out = buffer;
return S_OK;
}
HRESULT CreateIndexBuffer(UINT length, DWORD, D3DFORMAT format, D3DPOOL, IDirect3DIndexBuffer8** out) override
{
auto* buffer = new DeviceIndexBuffer();
buffer->bytes.resize(length);
buffer->format = format;
*out = buffer;
return S_OK;
}
HRESULT CreateDepthStencilSurface(UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE, IDirect3DSurface8** out) override
{
auto* surface = new CpuSurface();
surface->desc = surface_desc(width, height, format, D3DUSAGE_DEPTHSTENCIL, D3DPOOL_DEFAULT);
*out = surface;
return S_OK;
}
HRESULT GetRenderTarget(IDirect3DSurface8** out) override
{
m_renderTarget->AddRef();
*out = m_renderTarget;
return S_OK;
}
HRESULT GetDepthStencilSurface(IDirect3DSurface8** out) override
{
m_depthStencil->AddRef();
*out = m_depthStencil;
return S_OK;
}
// PORT: an offscreen target (CSnowEnvironment's blur pass) swallows its draws; only the back
// buffer's draws are recorded for the Godot renderer.
HRESULT SetRenderTarget(IDirect3DSurface8* target, IDirect3DSurface8* depth) override
{
if (target)
{
target->AddRef();
m_renderTarget->Release();
m_renderTarget = target;
}
if (depth)
{
depth->AddRef();
m_depthStencil->Release();
m_depthStencil = depth;
}
return S_OK;
}
HRESULT Clear(DWORD, const D3DRECT*, DWORD, D3DCOLOR, float, DWORD) override { return S_OK; }
HRESULT SetRenderState(D3DRENDERSTATETYPE state, DWORD value) override
{
if (unsigned(state) < kRenderStates)
@@ -237,10 +476,118 @@ private:
return true;
}
static void transform_point(const float v[4], const float m[16], float out[4])
{
for (int c = 0; c < 4; ++c)
out[c] = v[0] * m[c] + v[1] * m[4 + c] + v[2] * m[8 + c] + v[3] * m[12 + c];
}
static void multiply(const float a[16], const float b[16], float out[16])
{
for (int r = 0; r < 4; ++r)
transform_point(&a[r * 4], b, &out[r * 4]);
}
// Each two-triangle quad of a UI-space draw becomes an image command: its screen corners through
// world * view * projection, its stage-0 texture (or D3DTA_TFACTOR colour when stage 0 selects it)
// and, when stage 1 generates coordinates from the camera-space position through D3DTS_TEXTURE1
// (the minimap's circular filter), the mask's coordinates at the corners.
void record_ui_quads(D3DPRIMITIVETYPE type, const uint8_t* vertices, size_t vertexBytes, UINT stride,
const VertexLayout& layout, const std::vector<std::uint32_t>& indices)
{
if (layout.uv0 < 0)
return;
unsigned width = 0, height = 0;
UIRenderGetSize(&width, &height);
float worldView[16], worldViewProj[16];
multiply(m_transforms[256], m_transforms[D3DTS_VIEW], worldView);
multiply(worldView, m_transforms[D3DTS_PROJECTION], worldViewProj);
const DWORD* stage0 = m_stageStates[0];
const DWORD* stage1 = m_stageStates[1];
const bool factorColor = stage0[D3DTSS_COLOROP] == D3DTOP_SELECTARG1 && stage0[D3DTSS_COLORARG1] == D3DTA_TFACTOR;
const std::uint32_t argb = factorColor ? (0xFF000000u | (m_renderStates[D3DRS_TEXTUREFACTOR] & 0x00FFFFFFu)) : 0xFFFFFFFFu;
const bool masked = m_textures[1] && (stage1[D3DTSS_TEXCOORDINDEX] & 0xFFFF0000u) == D3DTSS_TCI_CAMERASPACEPOSITION &&
stage1[D3DTSS_TEXTURETRANSFORMFLAGS] == D3DTTFF_COUNT2 && stage1[D3DTSS_COLOROP] == D3DTOP_MODULATE &&
stage1[D3DTSS_ALPHAOP] == D3DTOP_SELECTARG1 && stage1[D3DTSS_ALPHAARG1] == D3DTA_TEXTURE;
const std::string texture = factorColor ? std::string() : UIRenderTextureNameFromHandle(m_textures[0]);
const std::string mask = masked ? UIRenderTextureNameFromHandle(m_textures[1]) : std::string();
std::vector<std::vector<std::uint32_t>> quads;
if (type == D3DPT_TRIANGLELIST)
for (size_t i = 0; i + 6 <= indices.size(); i += 6)
quads.push_back({ indices.begin() + i, indices.begin() + i + 6 });
else if (type == D3DPT_TRIANGLESTRIP && indices.size() == 4)
quads.push_back(indices);
for (const auto& quad : quads)
{
std::vector<std::uint32_t> corners;
for (std::uint32_t index : quad)
if (std::find(corners.begin(), corners.end(), index) == corners.end())
corners.push_back(index);
if (corners.size() != 4)
continue;
float sx[4], sy[4], u[4], v[4], mu[4] = {}, mv[4] = {};
bool inside = true;
for (int i = 0; i < 4; ++i)
{
const size_t offset = size_t(corners[i]) * stride;
if (offset + stride > vertexBytes) { inside = false; break; }
const uint8_t* vertex = vertices + offset;
float position[4] = { 0, 0, 0, 1 }, clip[4], camera[4], coord[4];
std::memcpy(position, vertex, 12);
std::memcpy(&u[i], vertex + layout.uv0, 4);
std::memcpy(&v[i], vertex + layout.uv0 + 4, 4);
transform_point(position, worldViewProj, clip);
if (clip[3] == 0.0f) { inside = false; break; }
sx[i] = (clip[0] / clip[3] * 0.5f + 0.5f) * float(width);
sy[i] = (0.5f - clip[1] / clip[3] * 0.5f) * float(height);
if (masked)
{
transform_point(position, worldView, camera);
camera[3] = 1.0f;
transform_point(camera, m_transforms[D3DTS_TEXTURE1], coord);
mu[i] = coord[0];
mv[i] = coord[1];
}
}
if (!inside)
continue;
UIRenderCommand command{UIRenderCommand::Image, 0, 0, 0, 0, argb};
command.su = *std::min_element(u, u + 4); command.eu = *std::max_element(u, u + 4);
command.sv = *std::min_element(v, v + 4); command.ev = *std::max_element(v, v + 4);
// Corners in the command's TL, TR, BL, BR order, by texture coordinate.
const float cu[4] = { command.su, command.eu, command.su, command.eu };
const float cv[4] = { command.sv, command.sv, command.ev, command.ev };
for (int c = 0; c < 4; ++c)
{
int best = 0;
float bestDistance = INFINITY;
for (int i = 0; i < 4; ++i)
{
const float distance = std::fabs(u[i] - cu[c]) + std::fabs(v[i] - cv[c]);
if (distance < bestDistance) { bestDistance = distance; best = i; }
}
command.qx[c] = sx[best]; command.qy[c] = sy[best];
command.mu[c] = mu[best]; command.mv[c] = mv[best];
}
command.x1 = *std::min_element(command.qx, command.qx + 4);
command.y1 = *std::min_element(command.qy, command.qy + 4);
command.x2 = *std::max_element(command.qx, command.qx + 4);
command.y2 = *std::max_element(command.qy, command.qy + 4);
command.text = texture;
command.quad = true;
command.mask = mask;
UIRenderAdd(std::move(command));
}
}
void record(D3DPRIMITIVETYPE type, UINT primitives, const uint8_t* vertices, size_t vertexBytes, UINT stride,
const std::vector<std::uint32_t>& indices)
{
if (type == D3DPT_POINTLIST || indices.empty() || !vertices)
if (type == D3DPT_POINTLIST || indices.empty() || !vertices || m_renderTarget != m_backBuffer)
return;
VertexLayout layout = fvf_layout(m_fvf);
if (!stride)
@@ -253,6 +600,14 @@ private:
if (layout.uv0 + 8 > int(stride)) layout.uv0 = -1;
if (layout.uv1 + 8 > int(stride)) layout.uv1 = -1;
// An orthographic projection over untransformed vertices is a UI-space draw (CPythonMiniMap's
// terrain tiles under CPythonGraphic::SetOrtho2D): it joins the UI command stream in order.
if (!layout.rhw && m_transforms[D3DTS_PROJECTION][11] == 0.0f)
{
record_ui_quads(type, vertices, vertexBytes, stride, layout, indices);
return;
}
Render3DDraw draw;
std::memcpy(draw.world, m_transforms[256], sizeof(draw.world)); // D3DTS_WORLD
std::memcpy(draw.view, m_transforms[D3DTS_VIEW], sizeof(draw.view));
@@ -340,7 +695,7 @@ private:
copy_color(draw.material_diffuse, m_material.Diffuse);
copy_color(draw.material_ambient, m_material.Ambient);
copy_color(draw.material_emissive, m_material.Emissive);
if (m_lights[0].Type == D3DLIGHT_DIRECTIONAL)
if (m_lightEnabled[0] && m_lights[0].Type == D3DLIGHT_DIRECTIONAL)
{
draw.light0 = true;
draw.light0_direction[0] = m_lights[0].Direction.x;
@@ -360,6 +715,11 @@ private:
IDirect3DBaseTexture8* m_textures[kStages] = {};
D3DMATERIAL8 m_material;
D3DLIGHT8 m_lights[8];
bool m_lightEnabled[8] = {};
IDirect3DSurface8* m_backBuffer = nullptr;
IDirect3DSurface8* m_depthBuffer = nullptr;
IDirect3DSurface8* m_renderTarget = nullptr;
IDirect3DSurface8* m_depthStencil = nullptr;
DWORD m_fvf = 0;
MtCpuVertexBuffer* m_stream = nullptr;
UINT m_streamStride = 0;
@@ -1,4 +1,6 @@
#include "EterLib/StdAfx.h"
#include "UIRenderCommands.h"
#include "EterLib/StateManager.h"
#include <algorithm>
@@ -39,10 +41,36 @@ void UIRenderRestoreClip() {
void UIRenderAddImage(const CGraphicTexture* texture, const float x[4], const float y[4],
float su, float sv, float eu, float ev, std::uint32_t argb, int blend) {
// 40250 draws the image quad through the device: the UI pass's world transform places it
// (identity except where a caller sets one, e.g. CPythonMiniMap::RenderAtlas's window offset) and a
// stage-0 MODULATE with D3DTA_TFACTOR tints it (the atlas's NPC/warp/waypoint marks).
D3DXMATRIX world;
D3DXMatrixIdentity(&world);
if (CStateManager* state = CStateManager::InstancePtr()) {
state->GetTransform(D3DTS_WORLD, &world);
DWORD op = 0, arg1 = 0, arg2 = 0;
state->GetTextureStageState(0, D3DTSS_COLOROP, &op);
state->GetTextureStageState(0, D3DTSS_COLORARG1, &arg1);
state->GetTextureStageState(0, D3DTSS_COLORARG2, &arg2);
if (op == D3DTOP_MODULATE && (arg1 == D3DTA_TFACTOR || arg2 == D3DTA_TFACTOR)) {
// TFACTOR x TEXTURE drops the vertex colour; TFACTOR x DIFFUSE scales it. The canvas
// multiplies the texture in.
const std::uint32_t factor = state->GetRenderState(D3DRS_TEXTUREFACTOR) & 0x00FFFFFFu;
const DWORD other = arg1 == D3DTA_TFACTOR ? arg2 : arg1;
if (other == D3DTA_DIFFUSE) {
std::uint32_t tinted = argb & 0xFF000000u;
for (int shift = 0; shift < 24; shift += 8)
tinted |= ((((argb >> shift) & 255) * ((factor >> shift) & 255) + 127) / 255) << shift;
argb = tinted;
} else {
argb = (argb & 0xFF000000u) | factor;
}
}
}
UIRenderCommand command{UIRenderCommand::Image, 0, 0, 0, 0, argb};
for (int i = 0; i < 4; ++i) {
command.qx[i] = x[i] + 0.5f;
command.qy[i] = y[i] + 0.5f;
command.qx[i] = x[i] * world._11 + y[i] * world._21 + world._41 + 0.5f;
command.qy[i] = x[i] * world._12 + y[i] * world._22 + world._42 + 0.5f;
}
command.x1 = std::min({command.qx[0], command.qx[1], command.qx[2], command.qx[3]});
command.y1 = std::min({command.qy[0], command.qy[1], command.qy[2], command.qy[3]});
@@ -18,6 +18,10 @@ struct UIRenderCommand {
float qx[4] = {}, qy[4] = {};
float su = 0, sv = 0, eu = 1, ev = 1;
int blend = 0; // CGraphicExpandedImageInstance::RENDERING_MODE_*
// A second texture stage that modulates the colour and replaces the alpha (40250 CPythonMiniMap's
// circular minimap_image_filter): the mask's texture coordinates at the quad's four corners.
std::string mask;
float mu[4] = {}, mv[4] = {};
};
// D3DXCOLOR (0..1 floats) -> the 0xAARRGGBB the commands carry.
@@ -0,0 +1,79 @@
// Platform implementation of 40250 GameLib/MapOutdoorCharacterShadow.cpp. The render-target lifecycle is
// the 40250 code as is; the shadow-map pass is not run (BeginRenderCharacterShadowToTexture reports it
// cannot render) because the terrain that samples the map is drawn by Godot, which casts its own
// character shadows (PORT-PLAN §3).
#include "GameLib/StdAfx.h"
#include "EterLib/StateManager.h"
#include "EterLib/Camera.h"
#include "GameLib/MapOutdoor.h"
static int recreate = false;
void CMapOutdoor::SetShadowTextureSize(WORD size)
{
if (m_wShadowMapSize != size)
{
recreate = true;
Tracenf("ShadowTextureSize changed %d -> %d", m_wShadowMapSize, size);
}
m_wShadowMapSize = size;
}
void CMapOutdoor::CreateCharacterShadowTexture()
{
extern bool GRAPHICS_CAPS_CAN_NOT_DRAW_SHADOW;
if (GRAPHICS_CAPS_CAN_NOT_DRAW_SHADOW)
return;
ReleaseCharacterShadowTexture();
if (IsLowTextureMemory())
SetShadowTextureSize(128);
m_ShadowMapViewport.X = 1;
m_ShadowMapViewport.Y = 1;
m_ShadowMapViewport.Width = m_wShadowMapSize - 2;
m_ShadowMapViewport.Height = m_wShadowMapSize - 2;
m_ShadowMapViewport.MinZ = 0.0f;
m_ShadowMapViewport.MaxZ = 1.0f;
if (FAILED(ms_lpd3dDevice->CreateTexture(m_wShadowMapSize, m_wShadowMapSize, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &m_lpCharacterShadowMapTexture)))
{
TraceError("CMapOutdoor Unable to create Character Shadow render target texture\n");
return;
}
if (FAILED(m_lpCharacterShadowMapTexture->GetSurfaceLevel(0, &m_lpCharacterShadowMapRenderTargetSurface)))
{
TraceError("CMapOutdoor Unable to GetSurfaceLevel Character Shadow render target texture\n");
return;
}
if (FAILED(ms_lpd3dDevice->CreateDepthStencilSurface(m_wShadowMapSize, m_wShadowMapSize, D3DFMT_D16, D3DMULTISAMPLE_NONE, &m_lpCharacterShadowMapDepthSurface)))
{
TraceError("CMapOutdoor Unable to create Character Shadow depth Surface\n");
return;
}
}
void CMapOutdoor::ReleaseCharacterShadowTexture()
{
SAFE_RELEASE(m_lpCharacterShadowMapRenderTargetSurface);
SAFE_RELEASE(m_lpCharacterShadowMapDepthSurface);
SAFE_RELEASE(m_lpCharacterShadowMapTexture);
}
// PORT: no shadow-map pass (see the file comment); CPythonBackground::RenderCharacterShadowToTexture
// then skips the shadow instances.
bool CMapOutdoor::BeginRenderCharacterShadowToTexture()
{
return false;
}
// PORT: nothing to restore when the pass did not begin.
void CMapOutdoor::EndRenderCharacterShadowToTexture()
{
}
@@ -0,0 +1,10 @@
// Platform implementation of 40250 GameLib/MapOutdoorRenderHTP.cpp (hardware-transform terrain patches).
// PORT: the Godot Metin2World adapter draws the terrain from the same .raw/.tga/tile data (PORT-PLAN §3):
// the recorder has no texture-coordinate generation or texture transforms, so the patch splat passes are
// not replayed through the D3D8 device.
#include "GameLib/StdAfx.h"
#include "GameLib/MapOutdoor.h"
void CMapOutdoor::__RenderTerrain_RenderHardwareTransformPatch()
{
}
@@ -0,0 +1,93 @@
// Platform implementation of 40250 GameLib/MapOutdoorRenderSTP.cpp (software-transform terrain patches).
// The vertex-buffer lifecycle is the 40250 code as is; the patch drawing is left to the Godot terrain
// (see MapOutdoorRenderHTP.cpp).
#include "GameLib/StdAfx.h"
#include "EterLib/StateManager.h"
#include "GameLib/MapOutdoor.h"
#include "GameLib/TerrainPatch.h"
struct SoftwareTransformPatch_SSplatVertex
{
D3DXVECTOR4 kPosition;
DWORD dwDiffuse;
DWORD dwSpecular;
D3DXVECTOR2 kTex1;
D3DXVECTOR2 kTex2;
};
// PORT: Godot draws the terrain (PORT-PLAN §3).
void CMapOutdoor::__RenderTerrain_RenderSoftwareTransformPatch()
{
}
void CMapOutdoor::__SoftwareTransformPatch_Initialize()
{
{
for (UINT uIndex=0; uIndex!=SoftwareTransformPatch_SData::SPLAT_VB_NUM; ++uIndex)
m_kSTPD.m_pkVBSplat[uIndex]=NULL;
m_kSTPD.m_dwSplatPos=0;
}
{
for (UINT uIndex=0; uIndex!=SoftwareTransformPatch_SData::NONE_VB_NUM; ++uIndex)
m_kSTPD.m_pkVBNone[uIndex]=NULL;
m_kSTPD.m_dwNonePos=0;
}
}
bool CMapOutdoor::__SoftwareTransformPatch_Create()
{
{
for (UINT uIndex=0; uIndex!=SoftwareTransformPatch_SData::SPLAT_VB_NUM; ++uIndex)
{
assert(NULL==m_kSTPD.m_pkVBSplat[uIndex]);
if (FAILED(
ms_lpd3dDevice->CreateVertexBuffer(
sizeof(SoftwareTransformPatch_SSplatVertex)*CTerrainPatch::TERRAIN_VERTEX_COUNT,
D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_SPECULAR|D3DFVF_TEX2,
D3DPOOL_SYSTEMMEM,
&m_kSTPD.m_pkVBSplat[uIndex]
)
)) return false;
}
}
{
for (UINT uIndex=0; uIndex!=SoftwareTransformPatch_SData::NONE_VB_NUM; ++uIndex)
{
assert(NULL==m_kSTPD.m_pkVBNone[uIndex]);
if (FAILED(
ms_lpd3dDevice->CreateVertexBuffer(
sizeof(SoftwareTransformPatch_STVertex)*CTerrainPatch::TERRAIN_VERTEX_COUNT,
D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
D3DFVF_XYZRHW,
D3DPOOL_SYSTEMMEM,
&m_kSTPD.m_pkVBNone[uIndex]
)
)) return false;
}
}
return true;
}
void CMapOutdoor::__SoftwareTransformPatch_Destroy()
{
{
for (UINT uIndex=0; uIndex!=SoftwareTransformPatch_SData::SPLAT_VB_NUM; ++uIndex)
{
if (m_kSTPD.m_pkVBSplat[uIndex])
m_kSTPD.m_pkVBSplat[uIndex]->Release();
}
}
{
for (UINT uIndex=0; uIndex!=SoftwareTransformPatch_SData::NONE_VB_NUM; ++uIndex)
{
if (m_kSTPD.m_pkVBNone[uIndex])
m_kSTPD.m_pkVBNone[uIndex]->Release();
}
}
__SoftwareTransformPatch_Initialize();
}
@@ -0,0 +1,30 @@
// Platform implementation of 40250 GameLib/MapOutdoorWater.cpp. The water texture set is loaded as in
// 40250; the water surface itself is drawn by the Godot water adapter (PORT-PLAN §3).
#include "GameLib/StdAfx.h"
#include "EterLib/StateManager.h"
#include "EterLib/ResourceManager.h"
#include "GameLib/MapOutdoor.h"
#include "GameLib/TerrainPatch.h"
void CMapOutdoor::LoadWaterTexture()
{
UnloadWaterTexture();
char buf[256];
for (int i = 0; i < 30; ++i)
{
sprintf(buf, "d:/ymir Work/special/water/%02d.dds", i+1);
m_WaterInstances[i].SetImagePointer((CGraphicImage *) CResourceManager::Instance().GetResourcePointer(buf));
}
}
void CMapOutdoor::UnloadWaterTexture()
{
for (int i = 0; i < 30; ++i)
m_WaterInstances[i].Destroy();
}
// PORT: the water patches are drawn by the Godot side.
void CMapOutdoor::RenderWater()
{
}
@@ -1,79 +0,0 @@
// Platform skeleton for GameLib/SnowEnvironment.h (40250 GameLib/SnowEnvironment.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
#include "GameLib/StdAfx.h"
#include "GameLib/SnowEnvironment.h"
#include "../PlatformStub.h"
CSnowEnvironment::CSnowEnvironment()
{
MT_PLATFORM_STUB();
}
CSnowEnvironment::~CSnowEnvironment()
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::Create() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CSnowEnvironment::Destroy() -> void
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::Enable() -> void
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::Disable() -> void
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::Update(const D3DXVECTOR3 &) -> void
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::Deform() -> void
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::Render() -> void
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::__Initialize() -> void
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::__CreateBlurTexture() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CSnowEnvironment::__CreateGeometry() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CSnowEnvironment::__BeginBlur() -> void
{
MT_PLATFORM_STUB();
}
auto CSnowEnvironment::__ApplyBlur() -> void
{
MT_PLATFORM_STUB();
}
@@ -1,31 +0,0 @@
// Platform skeleton for GameLib/TerrainDecal.h (40250 GameLib/TerrainDecal.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
#include "GameLib/StdAfx.h"
#include "GameLib/TerrainDecal.h"
#include "../PlatformStub.h"
CTerrainDecal::CTerrainDecal(CMapOutdoor *)
{
MT_PLATFORM_STUB();
}
CTerrainDecal::~CTerrainDecal()
{
MT_PLATFORM_STUB();
}
auto CTerrainDecal::Make(D3DXVECTOR3, D3DXVECTOR3, D3DXVECTOR3, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainDecal::Render() -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainDecal::SearchAffectedTerrainMesh(float, float, float, float, DWORD *, D3DXVECTOR3 *, D3DXVECTOR3 *) -> void
{
MT_PLATFORM_STUB();
}
@@ -1,118 +0,0 @@
// Platform skeleton for GameLib/TerrainPatch.h (40250 GameLib/TerrainPatch.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
#include "GameLib/StdAfx.h"
#include "GameLib/TerrainPatch.h"
#include "../PlatformStub.h"
decltype(CTerrainPatch::SOFTWARE_TRANSFORM_PATCH_ENABLE) CTerrainPatch::SOFTWARE_TRANSFORM_PATCH_ENABLE{};
auto CTerrainPatch::Clear() -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatch::GetWaterFaceCount() -> UINT
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<UINT>();
}
auto CTerrainPatch::SoftwareTransformPatch_UpdateTerrainLighting(DWORD, const D3DLIGHT8 &, const D3DMATERIAL8 &) -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatch::BuildTerrainVertexBuffer(HardwareTransformPatch_SSourceVertex *) -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatch::BuildWaterVertexBuffer(SWaterVertex *, UINT) -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatch::__BuildHardwareTerrainVertexBuffer(HardwareTransformPatch_SSourceVertex *) -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatch::__BuildSoftwareTerrainVertexBuffer(HardwareTransformPatch_SSourceVertex *) -> void
{
MT_PLATFORM_STUB();
}
CTerrainPatch::SSoftwareTransformPatch::SSoftwareTransformPatch()
{
MT_PLATFORM_STUB();
}
CTerrainPatch::SSoftwareTransformPatch::~SSoftwareTransformPatch()
{
MT_PLATFORM_STUB();
}
auto CTerrainPatch::SSoftwareTransformPatch::Create() -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatch::SSoftwareTransformPatch::Destroy() -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatch::SSoftwareTransformPatch::__Initialize() -> void
{
MT_PLATFORM_STUB();
}
CTerrainPatchProxy::CTerrainPatchProxy()
{
MT_PLATFORM_STUB();
}
CTerrainPatchProxy::~CTerrainPatchProxy()
{
MT_PLATFORM_STUB();
}
auto CTerrainPatchProxy::Clear() -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatchProxy::SetCenterPosition(const D3DXVECTOR3 &) -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainPatchProxy::IsIn(const D3DXVECTOR3 &, float) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTerrainPatchProxy::GetWaterFaceCount() -> UINT
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<UINT>();
}
auto CTerrainPatchProxy::SoftwareTransformPatch_GetTerrainVertexDataPtr() -> SoftwareTransformPatch_SSourceVertex *
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<SoftwareTransformPatch_SSourceVertex *>();
}
auto CTerrainPatchProxy::HardwareTransformPatch_GetVertexBufferPtr() -> CGraphicVertexBuffer *
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<CGraphicVertexBuffer *>();
}
auto CTerrainPatchProxy::SoftwareTransformPatch_UpdateTerrainLighting(DWORD, const D3DLIGHT8 &, const D3DMATERIAL8 &) -> void
{
MT_PLATFORM_STUB();
}
@@ -1,80 +0,0 @@
// Platform skeleton for PRTerrainLib/Terrain.h (40250 PRTerrainLib/Terrain.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
#include "PRTerrainLib/StdAfx.h"
#include "PRTerrainLib/Terrain.h"
#include "../PlatformStub.h"
auto CTerrainImpl::SetTextureSet(CTextureSet *) -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainImpl::GetTextureSet() -> CTextureSet *
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<CTextureSet *>();
}
decltype(CTerrainImpl::ms_pTextureSet) CTerrainImpl::ms_pTextureSet{};
CTerrainImpl::CTerrainImpl()
{
MT_PLATFORM_STUB();
}
CTerrainImpl::~CTerrainImpl()
{
MT_PLATFORM_STUB();
}
auto CTerrainImpl::LoadWaterMap(const char *) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTerrainImpl::LoadWaterMapFile(const char *) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTerrainImpl::GetShadowMapColor(float, float) -> DWORD
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
}
auto CTerrainImpl::Initialize() -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainImpl::Clear() -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainImpl::LoadTextures() -> void
{
MT_PLATFORM_STUB();
}
auto CTerrainImpl::LoadHeightMap(const char *) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTerrainImpl::RAW_LoadTileMap(const char *) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTerrainImpl::LoadAttrMap(const char *) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
@@ -1,83 +0,0 @@
// Platform skeleton for PRTerrainLib/TextureSet.h (40250 PRTerrainLib/TextureSet.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
#include "PRTerrainLib/StdAfx.h"
#include "PRTerrainLib/TextureSet.h"
#include "../PlatformStub.h"
CTextureSet::CTextureSet()
{
MT_PLATFORM_STUB();
}
CTextureSet::~CTextureSet()
{
MT_PLATFORM_STUB();
}
auto CTextureSet::Initialize() -> void
{
MT_PLATFORM_STUB();
}
auto CTextureSet::Clear() -> void
{
MT_PLATFORM_STUB();
}
auto CTextureSet::Create() -> void
{
MT_PLATFORM_STUB();
}
auto CTextureSet::Load(const char *, float) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTextureSet::Save(const char *) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTextureSet::GetTextureCount() -> unsigned long
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<unsigned long>();
}
auto CTextureSet::GetTexture(unsigned long) -> TTerrainTexture &
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<TTerrainTexture &>();
}
auto CTextureSet::RemoveTexture(unsigned long) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTextureSet::SetTexture(unsigned long, const char *, float, float, float, float, bool, unsigned short, unsigned short, float) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTextureSet::Reload(float) -> void
{
MT_PLATFORM_STUB();
}
auto CTextureSet::AddTexture(const char *, float, float, float, float, bool, unsigned short, unsigned short, float) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CTextureSet::AddEmptyTexture() -> void
{
MT_PLATFORM_STUB();
}
@@ -35,36 +35,6 @@
#include "UserInterface/PythonTextTail.h"
// 40250 UserInterface/PythonBackgroundModule.cpp
void AddStubConstants_background(PyObject* poModule)
{
(void) poModule;
PyModule_AddIntConstant(poModule, "PART_SKY", CMapOutdoor::PART_SKY);
PyModule_AddIntConstant(poModule, "PART_TREE", CMapOutdoor::PART_TREE);
PyModule_AddIntConstant(poModule, "PART_CLOUD", CMapOutdoor::PART_CLOUD);
PyModule_AddIntConstant(poModule, "PART_WATER", CMapOutdoor::PART_WATER);
PyModule_AddIntConstant(poModule, "PART_OBJECT", CMapOutdoor::PART_OBJECT);
PyModule_AddIntConstant(poModule, "PART_TERRAIN", CMapOutdoor::PART_TERRAIN);
PyModule_AddIntConstant(poModule, "SKY_RENDER_MODE_DEFAULT", CSkyObject::SKY_RENDER_MODE_DEFAULT);
PyModule_AddIntConstant(poModule, "SKY_RENDER_MODE_DIFFUSE", CSkyObject::SKY_RENDER_MODE_DIFFUSE);
PyModule_AddIntConstant(poModule, "SKY_RENDER_MODE_TEXTURE", CSkyObject::SKY_RENDER_MODE_TEXTURE);
PyModule_AddIntConstant(poModule, "SKY_RENDER_MODE_MODULATE", CSkyObject::SKY_RENDER_MODE_MODULATE);
PyModule_AddIntConstant(poModule, "SKY_RENDER_MODE_MODULATE2X", CSkyObject::SKY_RENDER_MODE_MODULATE2X);
PyModule_AddIntConstant(poModule, "SKY_RENDER_MODE_MODULATE4X", CSkyObject::SKY_RENDER_MODE_MODULATE4X);
PyModule_AddIntConstant(poModule, "SHADOW_NONE", CPythonBackground::SHADOW_NONE);
PyModule_AddIntConstant(poModule, "SHADOW_GROUND", CPythonBackground::SHADOW_GROUND);
PyModule_AddIntConstant(poModule, "SHADOW_GROUND_AND_SOLO", CPythonBackground::SHADOW_GROUND_AND_SOLO);
PyModule_AddIntConstant(poModule, "SHADOW_ALL", CPythonBackground::SHADOW_ALL);
PyModule_AddIntConstant(poModule, "SHADOW_ALL_HIGH", CPythonBackground::SHADOW_ALL_HIGH);
PyModule_AddIntConstant(poModule, "SHADOW_ALL_MAX", CPythonBackground::SHADOW_ALL_MAX);
PyModule_AddIntConstant(poModule, "DISTANCE0", CPythonBackground::DISTANCE0);
PyModule_AddIntConstant(poModule, "DISTANCE1", CPythonBackground::DISTANCE1);
PyModule_AddIntConstant(poModule, "DISTANCE2", CPythonBackground::DISTANCE2);
PyModule_AddIntConstant(poModule, "DISTANCE3", CPythonBackground::DISTANCE3);
PyModule_AddIntConstant(poModule, "DISTANCE4", CPythonBackground::DISTANCE4);
PyModule_AddIntConstant(poModule, "DISTANCE_SORT", CMapOutdoor::DISTANCE_SORT);
PyModule_AddIntConstant(poModule, "TEXTURE_SORT", CMapOutdoor::TEXTURE_SORT);
}
// 40250 UserInterface/PythonEventManagerMoudle.cpp
void AddStubConstants_event(PyObject* poModule)
{
@@ -5,7 +5,6 @@
#include "../EterLib/UIRenderCommands.h"
// GameplayModuleConstants.cpp: each module's 40250 constants.
void AddStubConstants_background(PyObject* poModule);
void AddStubConstants_event(PyObject* poModule);
void AddStubConstants_eventMgr(PyObject* poModule);
void AddStubConstants_guild(PyObject* poModule);
@@ -27,106 +26,6 @@ PyObject* stub_call_named(const char* name, PyObject* result = nullptr) {
return result ? result : Py_BuildValue("i", 0);
}
// 40250 UserInterface/PythonBackgroundModule.cpp: background export names.
PyObject* stub_background_IsSoftwareTiling(PyObject*, PyObject*) { return stub_call_named("background.IsSoftwareTiling", Py_BuildValue("i", 0)); }
PyObject* stub_background_EnableSoftwareTiling(PyObject*, PyObject*) { return stub_call_named("background.EnableSoftwareTiling", Py_BuildNone()); }
PyObject* stub_background_EnableSnow(PyObject*, PyObject*) { return stub_call_named("background.EnableSnow", Py_BuildNone()); }
PyObject* stub_background_GlobalPositionToLocalPosition(PyObject*, PyObject*) { return stub_call_named("background.GlobalPositionToLocalPosition", Py_BuildValue("ii", 0, 0)); }
PyObject* stub_background_GlobalPositionToMapInfo(PyObject*, PyObject*) { return stub_call_named("background.GlobalPositionToMapInfo", Py_BuildValue("sii", "", 0, 0)); }
PyObject* stub_background_GetRenderShadowTime(PyObject*, PyObject*) { return stub_call_named("background.GetRenderShadowTime", Py_BuildValue("i", 0)); }
PyObject* stub_background_LoadMap(PyObject*, PyObject*) { return stub_call_named("background.LoadMap", Py_BuildNone()); }
PyObject* stub_background_Destroy(PyObject*, PyObject*) { return stub_call_named("background.Destroy", Py_BuildNone()); }
PyObject* stub_background_RegisterEnvironmentData(PyObject*, PyObject*) { return stub_call_named("background.RegisterEnvironmentData", Py_BuildNone()); }
PyObject* stub_background_SetEnvironmentData(PyObject*, PyObject*) { return stub_call_named("background.SetEnvironmentData", Py_BuildNone()); }
PyObject* stub_background_GetCurrentMapName(PyObject*, PyObject*) { return stub_call_named("background.GetCurrentMapName", Py_BuildValue("s", "")); }
PyObject* stub_background_GetPickingPoint(PyObject*, PyObject*) { return stub_call_named("background.GetPickingPoint", Py_BuildValue("fff", 0.0, 0.0, 0.0)); }
PyObject* stub_background_BeginEnvironment(PyObject*, PyObject*) { return stub_call_named("background.BeginEnvironment", Py_BuildNone()); }
PyObject* stub_background_EndEnvironment(PyObject*, PyObject*) { return stub_call_named("background.EndEnvironment", Py_BuildNone()); }
PyObject* stub_background_SetCharacterDirLight(PyObject*, PyObject*) { return stub_call_named("background.SetCharacterDirLight", Py_BuildNone()); }
PyObject* stub_background_SetBackgroundDirLight(PyObject*, PyObject*) { return stub_call_named("background.SetBackgroundDirLight", Py_BuildNone()); }
PyObject* stub_background_Initialize(PyObject*, PyObject*) { return stub_call_named("background.Initialize", Py_BuildNone()); }
PyObject* stub_background_Update(PyObject*, PyObject*) { return stub_call_named("background.Update", Py_BuildNone()); }
PyObject* stub_background_Render(PyObject*, PyObject*) { return stub_call_named("background.Render", Py_BuildNone()); }
PyObject* stub_background_RenderPCBlocker(PyObject*, PyObject*) { return stub_call_named("background.RenderPCBlocker", Py_BuildNone()); }
PyObject* stub_background_RenderCollision(PyObject*, PyObject*) { return stub_call_named("background.RenderCollision", Py_BuildNone()); }
PyObject* stub_background_RenderSky(PyObject*, PyObject*) { return stub_call_named("background.RenderSky", Py_BuildNone()); }
PyObject* stub_background_RenderCloud(PyObject*, PyObject*) { return stub_call_named("background.RenderCloud", Py_BuildNone()); }
PyObject* stub_background_RenderWater(PyObject*, PyObject*) { return stub_call_named("background.RenderWater", Py_BuildNone()); }
PyObject* stub_background_RenderEffect(PyObject*, PyObject*) { return stub_call_named("background.RenderEffect", Py_BuildNone()); }
PyObject* stub_background_RenderBeforeLensFlare(PyObject*, PyObject*) { return stub_call_named("background.RenderBeforeLensFlare", Py_BuildNone()); }
PyObject* stub_background_RenderAfterLensFlare(PyObject*, PyObject*) { return stub_call_named("background.RenderAfterLensFlare", Py_BuildNone()); }
PyObject* stub_background_RenderCharacterShadowToTexture(PyObject*, PyObject*) { return stub_call_named("background.RenderCharacterShadowToTexture", Py_BuildNone()); }
PyObject* stub_background_RenderDungeon(PyObject*, PyObject*) { return stub_call_named("background.RenderDungeon", Py_BuildNone()); }
PyObject* stub_background_GetHeight(PyObject*, PyObject*) { return stub_call_named("background.GetHeight", Py_BuildValue("f", 0.0)); }
PyObject* stub_background_SetShadowLevel(PyObject*, PyObject*) { return stub_call_named("background.SetShadowLevel", Py_BuildNone()); }
PyObject* stub_background_SetVisiblePart(PyObject*, PyObject*) { return stub_call_named("background.SetVisiblePart", Py_BuildNone()); }
PyObject* stub_background_GetShadowMapColor(PyObject*, PyObject*) { return stub_call_named("background.GetShadowMapColor", Py_BuildValue("i", 0)); }
PyObject* stub_background_SetSplatLimit(PyObject*, PyObject*) { return stub_call_named("background.SetSplatLimit", Py_BuildNone()); }
PyObject* stub_background_GetRenderedSplatNum(PyObject*, PyObject*) { return stub_call_named("background.GetRenderedSplatNum", Py_BuildValue("iifs", 0, 0, 0.0, "")); }
PyObject* stub_background_GetRenderedGraphicThingInstanceNum(PyObject*, PyObject*) { return stub_call_named("background.GetRenderedGraphicThingInstanceNum", Py_BuildValue("ii", 0, 0)); }
PyObject* stub_background_SelectViewDistanceNum(PyObject*, PyObject*) { return stub_call_named("background.SelectViewDistanceNum", Py_BuildNone()); }
PyObject* stub_background_SetViewDistanceSet(PyObject*, PyObject*) { return stub_call_named("background.SetViewDistanceSet", Py_BuildNone()); }
PyObject* stub_background_GetFarClip(PyObject*, PyObject*) { return stub_call_named("background.GetFarClip", Py_BuildValue("f", 0.0)); }
PyObject* stub_background_GetDistanceSetInfo(PyObject*, PyObject*) { return stub_call_named("background.GetDistanceSetInfo", Py_BuildValue("ifff", 0, 0.0, 0.0, 0.0)); }
PyObject* stub_background_SetBGLoading(PyObject*, PyObject*) { return stub_call_named("background.SetBGLoading", Py_BuildNone()); }
PyObject* stub_background_SetRenderSort(PyObject*, PyObject*) { return stub_call_named("background.SetRenderSort", Py_BuildNone()); }
PyObject* stub_background_SetTransparentTree(PyObject*, PyObject*) { return stub_call_named("background.SetTransparentTree", Py_BuildNone()); }
PyObject* stub_background_SetXMasTree(PyObject*, PyObject*) { return stub_call_named("background.SetXMasTree", Py_BuildNone()); }
PyObject* stub_background_RegisterDungeonMapName(PyObject*, PyObject*) { return stub_call_named("background.RegisterDungeonMapName", Py_BuildNone()); }
PyObject* stub_background_VisibleGuildArea(PyObject*, PyObject*) { return stub_call_named("background.VisibleGuildArea", Py_BuildNone()); }
PyObject* stub_background_DisableGuildArea(PyObject*, PyObject*) { return stub_call_named("background.DisableGuildArea", Py_BuildNone()); }
PyObject* stub_background_WarpTest(PyObject*, PyObject*) { return stub_call_named("background.WarpTest", Py_BuildNone()); }
PyMethodDef methods_background[] = {
{ "IsSoftwareTiling", stub_background_IsSoftwareTiling, METH_VARARGS },
{ "EnableSoftwareTiling", stub_background_EnableSoftwareTiling, METH_VARARGS },
{ "EnableSnow", stub_background_EnableSnow, METH_VARARGS },
{ "GlobalPositionToLocalPosition", stub_background_GlobalPositionToLocalPosition, METH_VARARGS },
{ "GlobalPositionToMapInfo", stub_background_GlobalPositionToMapInfo, METH_VARARGS },
{ "GetRenderShadowTime", stub_background_GetRenderShadowTime, METH_VARARGS },
{ "LoadMap", stub_background_LoadMap, METH_VARARGS },
{ "Destroy", stub_background_Destroy, METH_VARARGS },
{ "RegisterEnvironmentData", stub_background_RegisterEnvironmentData, METH_VARARGS },
{ "SetEnvironmentData", stub_background_SetEnvironmentData, METH_VARARGS },
{ "GetCurrentMapName", stub_background_GetCurrentMapName, METH_VARARGS },
{ "GetPickingPoint", stub_background_GetPickingPoint, METH_VARARGS },
{ "BeginEnvironment", stub_background_BeginEnvironment, METH_VARARGS },
{ "EndEnvironment", stub_background_EndEnvironment, METH_VARARGS },
{ "SetCharacterDirLight", stub_background_SetCharacterDirLight, METH_VARARGS },
{ "SetBackgroundDirLight", stub_background_SetBackgroundDirLight, METH_VARARGS },
{ "Initialize", stub_background_Initialize, METH_VARARGS },
{ "Update", stub_background_Update, METH_VARARGS },
{ "Render", stub_background_Render, METH_VARARGS },
{ "RenderPCBlocker", stub_background_RenderPCBlocker, METH_VARARGS },
{ "RenderCollision", stub_background_RenderCollision, METH_VARARGS },
{ "RenderSky", stub_background_RenderSky, METH_VARARGS },
{ "RenderCloud", stub_background_RenderCloud, METH_VARARGS },
{ "RenderWater", stub_background_RenderWater, METH_VARARGS },
{ "RenderEffect", stub_background_RenderEffect, METH_VARARGS },
{ "RenderBeforeLensFlare", stub_background_RenderBeforeLensFlare, METH_VARARGS },
{ "RenderAfterLensFlare", stub_background_RenderAfterLensFlare, METH_VARARGS },
{ "RenderCharacterShadowToTexture", stub_background_RenderCharacterShadowToTexture, METH_VARARGS },
{ "RenderDungeon", stub_background_RenderDungeon, METH_VARARGS },
{ "GetHeight", stub_background_GetHeight, METH_VARARGS },
{ "SetShadowLevel", stub_background_SetShadowLevel, METH_VARARGS },
{ "SetVisiblePart", stub_background_SetVisiblePart, METH_VARARGS },
{ "GetShadowMapColor", stub_background_GetShadowMapColor, METH_VARARGS },
{ "SetSplatLimit", stub_background_SetSplatLimit, METH_VARARGS },
{ "GetRenderedSplatNum", stub_background_GetRenderedSplatNum, METH_VARARGS },
{ "GetRenderedGraphicThingInstanceNum", stub_background_GetRenderedGraphicThingInstanceNum, METH_VARARGS },
{ "SelectViewDistanceNum", stub_background_SelectViewDistanceNum, METH_VARARGS },
{ "SetViewDistanceSet", stub_background_SetViewDistanceSet, METH_VARARGS },
{ "GetFarClip", stub_background_GetFarClip, METH_VARARGS },
{ "GetDistanceSetInfo", stub_background_GetDistanceSetInfo, METH_VARARGS },
{ "SetBGLoading", stub_background_SetBGLoading, METH_VARARGS },
{ "SetRenderSort", stub_background_SetRenderSort, METH_VARARGS },
{ "SetTransparentTree", stub_background_SetTransparentTree, METH_VARARGS },
{ "SetXMasTree", stub_background_SetXMasTree, METH_VARARGS },
{ "RegisterDungeonMapName", stub_background_RegisterDungeonMapName, METH_VARARGS },
{ "VisibleGuildArea", stub_background_VisibleGuildArea, METH_VARARGS },
{ "DisableGuildArea", stub_background_DisableGuildArea, METH_VARARGS },
{ "WarpTest", stub_background_WarpTest, METH_VARARGS },
{ NULL, NULL }
};
// 40250 UserInterface/PythonEventManagerMoudle.cpp: event export names.
PyObject* stub_event_RegisterEventSet(PyObject*, PyObject*) { return stub_call_named("event.RegisterEventSet", Py_BuildValue("i", 0)); }
PyObject* stub_event_RegisterEventSetFromString(PyObject*, PyObject*) { return stub_call_named("event.RegisterEventSetFromString", Py_BuildValue("i", 0)); }
@@ -557,11 +456,6 @@ PyMethodDef methods_udp[] = {
} // namespace
void init_2v0_gameplay_stubs() {
{
PyObject* module = Py_InitModule("background", methods_background);
PyModule_AddIntConstant(module, "__port_stub__", 1);
AddStubConstants_background(module);
}
{
PyObject* module = Py_InitModule("event", methods_event);
PyModule_AddIntConstant(module, "__port_stub__", 1);
@@ -359,6 +359,7 @@ bool run_main_script_body(const char* lpCmdLine, std::string* error)
initeffect();
initfly();
initskill();
initBackground();
initServerStateChecker();
init_2v0_gameplay_stubs();
@@ -1,362 +0,0 @@
// Stand-in for the 40250 logic unit GameLib/MapManager.cpp, not ported yet: the members the ported units
// reference, as platform_stub.py stubs. Delete this file in the commit that ports the unit into port/
// (docs/PORT-PLAN.md).
#include "GameLib/StdAfx.h"
#include "GameLib/MapManager.h"
#include "EterPack/EterPackManager.h"
#include "EterBase/MappedFile.h"
#include "EterLib/StateManager.h"
#include "GameLib/MapUtil.h"
#include <map_setting.h>
#include <terrain_files.h>
#include <terrain_mesh.h>
#include <algorithm>
#include <cmath>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include "../../PlatformStub.h"
namespace {
// PORT: The Godot terrain adapter owns drawing until CMapOutdoor is ported. This
// pack-backed state supplies its 40250 callers with the same height and .msenv
// data during that transition; it is not a CMapOutdoor port.
struct NativeMapState {
fmt::MapSetting setting;
std::string name;
std::map<std::pair<int, int>, fmt::HeightMap> heights;
std::map<std::pair<int, int>, std::vector<BYTE>> attrs; // attr.atr payload, empty when unreadable
bool ready = false;
};
std::map<const CMapManager *, NativeMapState> s_native_maps;
bool pack_bytes(const std::string &name, std::string &out)
{
CMappedFile file;
LPCVOID data = nullptr;
if (!CEterPackManager::Instance().Get(file, name.c_str(), &data))
return false;
out.assign(static_cast<const char *>(data), file.Size());
return true;
}
bool load_height_tile(NativeMapState &state, int tx, int ty)
{
if (tx < 0 || ty < 0 || tx >= state.setting.map_size_x || ty >= state.setting.map_size_y)
return false;
const auto key = std::make_pair(tx, ty);
if (state.heights.find(key) != state.heights.end())
return true;
char tile[16];
snprintf(tile, sizeof(tile), "%03d%03d", tx, ty);
std::string bytes;
if (!pack_bytes(state.name + "/" + tile + "/height.raw", bytes) || bytes.size() != 131 * 131 * 2)
return false;
fmt::HeightMap map;
map.raw.resize(131 * 131);
for (size_t i = 0; i < map.raw.size(); ++i)
map.raw[i] = static_cast<unsigned char>(bytes[i * 2]) |
(static_cast<unsigned char>(bytes[i * 2 + 1]) << 8);
state.heights.emplace(key, std::move(map));
return true;
}
// attr.atr: {u16 magic=2634, u16 w=256, u16 h=256} + 256*256 bytes (40250 CTerrainImpl::LoadAttrMap).
const std::vector<BYTE> *attr_tile(NativeMapState &state, int tx, int ty)
{
if (tx < 0 || ty < 0 || tx >= state.setting.map_size_x || ty >= state.setting.map_size_y)
return nullptr;
const auto key = std::make_pair(tx, ty);
auto found = state.attrs.find(key);
if (found == state.attrs.end())
{
char tile[16];
snprintf(tile, sizeof(tile), "%03d%03d", tx, ty);
std::string bytes;
std::vector<BYTE> attr;
const size_t payload = size_t(CTerrainImpl::ATTRMAP_XSIZE) * CTerrainImpl::ATTRMAP_YSIZE;
if (pack_bytes(state.name + "/" + tile + "/attr.atr", bytes) && bytes.size() == 6 + payload &&
(static_cast<unsigned char>(bytes[0]) | (static_cast<unsigned char>(bytes[1]) << 8)) == 2634)
attr.assign(bytes.begin() + 6, bytes.end());
found = state.attrs.emplace(key, std::move(attr)).first;
}
return found->second.empty() ? nullptr : &found->second;
}
}
// CMapOutdoor::GetHeight is max(terrain, object height under CCullingManager); no map objects are registered
// until CMapOutdoor is ported, so it is the terrain height.
auto CMapManager::GetHeight(float fx, float fy) -> float
{
return GetTerrainHeight(fx, fy);
}
// CMapOutdoor::GetTerrainHeight over the native height tiles.
auto CMapManager::GetTerrainHeight(float fx, float fy) -> float
{
auto found = s_native_maps.find(this);
if (found == s_native_maps.end() || !found->second.ready)
return 0.0f;
NativeMapState &state = found->second;
const double x = fx, y = std::abs(double(fy));
if (x < 0 || y < 0)
return 0.0f;
const int tx = int(x / 25600.0), ty = int(y / 25600.0);
if (!load_height_tile(state, tx, ty))
return 0.0f;
const float height = float(fmt::terrain_height_at(state.heights.at({tx, ty}), x - tx * 25600.0,
y - ty * 25600.0, state.setting.height_scale));
return height;
}
// CMapOutdoor::GetNormal → CTerrain::GetNormal. 40250 fills CTerrain::m_acNormalMap at LoadHeightMap with
// CTerrain::CalculateNormal and reads the cell's byte triple; the same formula runs here per call on the
// cached height tile (GetHeightMapValue = raw[(y+1)*131 + x+1]).
bool CMapManager::GetNormal(int ix, int iy, D3DXVECTOR3 * pv3Normal)
{
auto found = s_native_maps.find(this);
if (found == s_native_maps.end() || !found->second.ready)
return false;
NativeMapState &state = found->second;
const int count_x = state.setting.map_size_x, count_y = state.setting.map_size_y;
ix = std::clamp(ix, 0, count_x * CTerrainImpl::TERRAIN_XSIZE);
iy = std::clamp(iy, 0, count_y * CTerrainImpl::TERRAIN_YSIZE);
const int tx = std::min(ix / CTerrainImpl::TERRAIN_XSIZE, count_x - 1);
const int ty = std::min(iy / CTerrainImpl::TERRAIN_YSIZE, count_y - 1);
if (!load_height_tile(state, tx, ty))
return false;
while (ix >= CTerrainImpl::TERRAIN_XSIZE)
ix -= CTerrainImpl::TERRAIN_XSIZE;
while (iy >= CTerrainImpl::TERRAIN_YSIZE)
iy -= CTerrainImpl::TERRAIN_YSIZE;
const int x = ix / CTerrainImpl::CELLSCALE, y = iy / CTerrainImpl::CELLSCALE;
const std::vector<uint16_t> &raw = state.heights.at({tx, ty}).raw;
auto height = [&](int sx, int sy) {
return float(raw[(sy + 1) * CTerrainImpl::HEIGHTMAP_RAW_XSIZE + sx + 1]);
};
D3DXVECTOR3 normal;
normal.x = -state.setting.height_scale * (height(x - 1, y) - height(x + 1, y));
normal.y = -state.setting.height_scale * (height(x, y - 1) - height(x, y + 1));
normal.z = 2.0f * static_cast<float>(CTerrainImpl::CELLSCALE);
normal *= 127.0f / D3DXVec3Length(&normal);
// PR_FLOAT_TO_INT (fistp, then one down when it rounded up) into the char normal map.
const signed char n[3] = {
static_cast<signed char>(int(std::floor(normal.x))),
static_cast<signed char>(int(std::floor(normal.y))),
static_cast<signed char>(int(std::floor(normal.z))),
};
pv3Normal->x = -((float)n[0]) * 0.007874016f;
pv3Normal->y = ((float)n[1]) * 0.007874016f;
pv3Normal->z = ((float)n[2]) * 0.007874016f;
return true;
}
CMapManager::CMapManager() : mc_pcurEnvironmentData(NULL)
{
m_pkMap = NULL;
m_isSoftwareTilingEnableReserved=false;
// Initialize();
}
CMapManager::~CMapManager()
{
Destroy();
}
void CMapManager::Initialize()
{
mc_pcurEnvironmentData = NULL;
__LoadMapInfoVector();
}
void CMapManager::Create()
{
// PORT: CMapOutdoor is still rendered by Metin2World, not this native object.
}
void CMapManager::Destroy()
{
Clear();
for (auto &entry : m_EnvironmentDataMap)
delete entry.second;
m_EnvironmentDataMap.clear();
}
void CMapManager::__LoadMapInfoVector()
{
std::string bytes;
if (!pack_bytes(m_stAtlasInfoFileName, bytes) && !pack_bytes("AtlasInfo.txt", bytes))
return;
std::istringstream lines(bytes);
std::string line;
m_kVct_kMapInfo.clear();
while (std::getline(lines, line)) {
std::istringstream fields(line);
TMapInfo info{};
if (!(fields >> info.m_strName >> info.m_dwBaseX >> info.m_dwBaseY >> info.m_dwSizeX >> info.m_dwSizeY))
continue;
info.m_dwEndX = info.m_dwBaseX + info.m_dwSizeX * 25600;
info.m_dwEndY = info.m_dwBaseY + info.m_dwSizeY * 25600;
m_kVct_kMapInfo.push_back(info);
}
}
auto CMapManager::Clear() -> void
{
s_native_maps.erase(this);
mc_pcurEnvironmentData = NULL;
}
auto CMapManager::AllocMap() -> CMapBase *
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<CMapBase *>();
}
auto CMapManager::LoadMap(const std::string &name, float x, float y, float) -> bool
{
NativeMapState next;
next.name = name;
std::string bytes, error;
if (!pack_bytes(name + "/setting.txt", bytes) || !fmt::parse_map_setting(bytes, next.setting, &error)) {
TraceError("native map setting failed: %s (%s)", name.c_str(), error.c_str());
return false;
}
if (!load_height_tile(next, int(x / 25600.0f), int(y / 25600.0f))) {
TraceError("native map height tile failed: %s (%d,%d)", name.c_str(), int(x / 25600.0f), int(y / 25600.0f));
return false;
}
for (auto &entry : m_EnvironmentDataMap)
delete entry.second;
m_EnvironmentDataMap.clear();
mc_pcurEnvironmentData = NULL;
if (!next.setting.environment.empty()) {
auto env = std::make_unique<TEnvironmentData>();
Environment_Init(*env);
const std::string env_path = "d:/ymir work/environment/" + next.setting.environment;
if (Environment_Load(*env, env_path.c_str())) {
m_EnvironmentDataMap[0] = env.release();
mc_pcurEnvironmentData = m_EnvironmentDataMap[0];
} else {
TraceError("native map environment failed: %s", env_path.c_str());
}
}
next.ready = true;
s_native_maps[this] = std::move(next);
return true;
}
auto CMapManager::isPhysicalCollision(const D3DXVECTOR3 &) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CMapManager::GetWaterHeight(int, int, long *) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CMapManager::GetShadowMapColor(float, float) -> DWORD
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
}
// 40250 MapManager.cpp:506 → CMapOutdoor::isAttrOn (MapOutdoor.cpp:1202).
bool CMapManager::isAttrOn(float fX, float fY, BYTE byAttr)
{
if (!IsMapReady())
return false;
// PORT: PR_FLOAT_TO_INT is x87 fistp (round to nearest) corrected down, i.e. floor.
return isAttrOn(int(std::floor(fX)), int(std::floor(fY)), byAttr);
}
// 40250 MapManager.cpp:524 → CMapOutdoor::isAttrOn (MapOutdoor.cpp:1220) → CTerrain::isAttrOn (AreaTerrain.cpp:487).
// PORT: CMapOutdoor/CTerrain are not ported; the terrain count and the attribute map come from the native map
// state (Setting.txt MapSize, <map>/<xxxyyy>/attr.atr) instead of the loaded CTerrain list.
bool CMapManager::isAttrOn(int iX, int iY, BYTE byAttr)
{
if (!IsMapReady())
return false;
auto state = s_native_maps.find(this);
if (state == s_native_maps.end() || !state->second.ready)
return false;
const int countX = state->second.setting.map_size_x, countY = state->second.setting.map_size_y;
if (iX < 0 || iY < 0 || iX > countX * CTerrainImpl::TERRAIN_XSIZE || iY > countY * CTerrainImpl::TERRAIN_YSIZE)
return false;
WORD wTerrainCoordX, wTerrainCoordY;
wTerrainCoordX = iX / CTerrainImpl::TERRAIN_XSIZE;
wTerrainCoordY = iY / CTerrainImpl::TERRAIN_YSIZE;
const std::vector<BYTE> *attr = attr_tile(state->second, wTerrainCoordX, wTerrainCoordY);
if (!attr)
return false;
WORD wLocalX, wLocalY;
wLocalX = (iX - wTerrainCoordX * CTerrainImpl::TERRAIN_XSIZE) / (CTerrainImpl::HALF_CELLSCALE);
wLocalY = (iY - wTerrainCoordY * CTerrainImpl::TERRAIN_YSIZE) / (CTerrainImpl::HALF_CELLSCALE);
if (wLocalX >= CTerrainImpl::ATTRMAP_XSIZE || wLocalY >= CTerrainImpl::ATTRMAP_YSIZE)
return false;
BYTE byMapAttr = (*attr)[wLocalY * CTerrainImpl::ATTRMAP_XSIZE + wLocalX];
if ( byAttr < 16 )
return (byMapAttr & byAttr) ? true : false;
else
{
if ( byAttr/16 == byMapAttr/16)
return true;
else
return false;
}
}
auto CMapManager::BeginEnvironment() -> void
{
if (!IsMapReady() || !mc_pcurEnvironmentData)
return;
STATEMANAGER.SaveRenderState(D3DRS_LIGHTING, TRUE);
STATEMANAGER.SetMaterial(&mc_pcurEnvironmentData->Material);
STATEMANAGER.SetLight(0, &mc_pcurEnvironmentData->DirLights[ENV_DIRLIGHT_BACKGROUND]);
// PORT: RecordingDevice stores SetLight but has no D3D LightEnable slot yet.
}
auto CMapManager::EndEnvironment() -> void
{
if (IsMapReady() && mc_pcurEnvironmentData)
STATEMANAGER.RestoreRenderState(D3DRS_LIGHTING);
}
// PORT: MapOutdoor is not allocated yet; report the pack-backed transition map's readiness.
bool CMapManager::IsMapReady()
{
auto found = s_native_maps.find(this);
return found != s_native_maps.end() && found->second.ready;
}
// 40250 MapManager.cpp: true when the current map is a CMapOutdoor. PORT: CMapOutdoor is not ported (the Godot
// terrain adapter draws the map), so there is no outdoor map object to hand out; false keeps the 40250 callers
// (CPythonMiniMap::Update/Render/LoadAtlas) on their "no outdoor map" path instead of reaching into one.
auto CMapManager::IsMapOutdoor() -> bool
{
MT_PLATFORM_STUB();
return false;
}
auto CMapManager::GetMapOutdoorRef() -> CMapOutdoor &
{
MT_PLATFORM_STUB();
// Never constructed (CMapOutdoor's constructor is not ported either); unreachable while IsMapOutdoor() is false.
alignas(CMapOutdoor) static unsigned char storage[sizeof(CMapOutdoor)];
return *reinterpret_cast<CMapOutdoor *>(storage);
}
@@ -1,18 +0,0 @@
// Stand-in for the 40250 logic unit GameLib/MapOutdoor.cpp, not ported yet: the members the ported units
// reference, as platform_stub.py stubs. Only reached behind CMapManager::IsMapOutdoor(), which is false until
// CMapOutdoor is ported. Delete this file in the commit that ports the unit into port/ (docs/PORT-PLAN.md).
#include "GameLib/StdAfx.h"
#include "GameLib/MapOutdoor.h"
#include "../../PlatformStub.h"
auto CMapOutdoor::GetTerrainPointer(BYTE, CTerrain **) -> BOOL
{
MT_PLATFORM_STUB();
return FALSE;
}
auto CMapOutdoor::GetBaseXY(DWORD *, DWORD *) -> void
{
MT_PLATFORM_STUB();
}
@@ -1,11 +0,0 @@
// Pending MapType.cpp dependency of InstanceBase; the full unit is not ported yet.
#include "GameLib/StdAfx.h"
#include "GameLib/MapType.h"
float SPixelPosition_CalculateDistanceSq3d(const TPixelPosition& left, const TPixelPosition& right)
{
float dx = left.x - right.x;
float dy = left.y - right.y;
float dz = left.z - right.z;
return dx * dx + dy * dy + dz * dz;
}
@@ -1,17 +0,0 @@
// Stand-in for the 40250 logic unit GameLib/PropertyManager.cpp, not ported yet: the members the ported units
// reference, as platform_stub.py stubs. Delete this file in the commit that ports the unit into port/
// (docs/PORT-PLAN.md).
#include "GameLib/StdAfx.h"
#include "GameLib/PropertyManager.h"
#include "../../PlatformStub.h"
CPropertyManager::CPropertyManager()
{
MT_PLATFORM_STUB();
}
CPropertyManager::~CPropertyManager()
{
MT_PLATFORM_STUB();
}
@@ -1,342 +0,0 @@
// Stand-in for the 40250 logic unit UserInterface/PythonBackground.cpp, not ported yet: the members the ported units
// reference, as platform_stub.py stubs. Delete this file in the commit that ports the unit into port/
// (docs/PORT-PLAN.md).
#include "UserInterface/StdAfx.h"
#include "UserInterface/PythonBackground.h"
#include "UserInterface/InstanceBase.h"
#include "EterLib/StateManager.h"
#include "../../PlatformStub.h"
auto CPythonBackground::Destroy() -> void
{
CMapManager::Destroy();
m_bVisibleGuildArea = FALSE;
}
auto CPythonBackground::Create() -> void
{
CMapManager::Create();
}
auto CPythonBackground::GlobalPositionToLocalPosition(LONG &x, LONG &y) -> void
{
x -= m_dwBaseX;
y -= m_dwBaseY;
}
auto CPythonBackground::LocalPositionToGlobalPosition(LONG &x, LONG &y) -> void
{
x += m_dwBaseX;
y += m_dwBaseY;
}
auto CPythonBackground::RefreshShadowLevel() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::Update(float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::ClearGuildArea() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RegisterGuildArea(int, int, int, int) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::CreateTargetEffect(DWORD, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::CreateTargetEffect(DWORD, long, long) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::DeleteTargetEffect(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::Warp(DWORD x, DWORD y) -> void
{
if (m_kVct_kMapInfo.empty())
Initialize();
auto found = std::find_if(m_kVct_kMapInfo.begin(), m_kVct_kMapInfo.end(),
[x, y](const TMapInfo &info) {
return x >= info.m_dwBaseX && x < info.m_dwEndX &&
y >= info.m_dwBaseY && y < info.m_dwEndY;
});
if (found == m_kVct_kMapInfo.end()) {
TraceError("NOT_FOUND_GLOBAL_POSITION(%u, %u)", x, y);
return;
}
if (!LoadMap(found->m_strName, float(x - found->m_dwBaseX),
float(y - found->m_dwBaseY), 0.0f)) {
TraceError("CPythonBackground::Warp map load failed: %s", found->m_strName.c_str());
return;
}
m_dwBaseX = found->m_dwBaseX;
m_dwBaseY = found->m_dwBaseY;
m_strMapName = found->m_strName;
}
auto CPythonBackground::GetWarpMapName() -> const char *
{
return m_strMapName.c_str();
}
CPythonBackground::CPythonBackground()
{
m_eViewDistanceNum=0;
m_dwBaseX=0;
m_dwBaseY=0;
m_bVisibleGuildArea=FALSE;
m_iXMasTreeGrade=0;
}
CPythonBackground::~CPythonBackground()
{
MT_PLATFORM_STUB();
}
// 40250 PythonBackground.cpp:547-608, verbatim. No map objects are registered with CCullingManager until
// CMapOutdoor is ported, so the checkers see no opponent and advancing is never blocked.
struct CollisionChecker
{
bool isBlocked;
CInstanceBase* pInstance;
CollisionChecker(CInstanceBase* pInstance) : pInstance(pInstance), isBlocked(false) {}
void operator () (CGraphicObjectInstance* pOpponent)
{
if (isBlocked)
return;
if (!pOpponent)
return;
if (pInstance->IsBlockObject(*pOpponent))
isBlocked=true;
}
};
struct CollisionAdjustChecker
{
bool isBlocked;
CInstanceBase* pInstance;
CollisionAdjustChecker(CInstanceBase* pInstance) : pInstance(pInstance), isBlocked(false) {}
void operator () (CGraphicObjectInstance* pOpponent)
{
if (!pOpponent)
return;
if (pInstance->AvoidObject(*pOpponent))
isBlocked=true;
}
};
bool CPythonBackground::CheckAdvancing(CInstanceBase * pInstance)
{
if (!IsMapReady())
return true;
Vector3d center;
float radius;
pInstance->GetGraphicThingInstanceRef().GetBoundingSphere(center,radius);
CCullingManager & rkCullingMgr = CCullingManager::Instance();
CollisionAdjustChecker kCollisionAdjustChecker(pInstance);
rkCullingMgr.ForInRange(center, radius, &kCollisionAdjustChecker);
if (kCollisionAdjustChecker.isBlocked)
{
CollisionChecker kCollisionChecker(pInstance);
rkCullingMgr.ForInRange(center, radius, &kCollisionChecker);
if (kCollisionChecker.isBlocked)
{
pInstance->BlockMovement();
return true;
}
else
{
pInstance->NEW_MoveToDestPixelPositionDirection(pInstance->NEW_GetDstPixelPositionRef());
}
return false;
}
return false;
}
namespace
{
// 40250 CMapOutdoor::__PickTerrainHeight (MapOutdoor.cpp:448), marching the ray against the terrain height.
// PORT: CMapOutdoor is not ported; the terrain is the native CMapManager height map, and GetTerrainNum/
// GetTerrainPointer become "the map is ready" (GetHeight reads the height tile under the point).
bool PickTerrainHeight(CMapManager& rkMap, float& fPos, const D3DXVECTOR3& v3Start, const D3DXVECTOR3& v3End, float fStep,
float fRayRange, float fLimitRange, D3DXVECTOR3* pv3Pick)
{
D3DXVECTOR3 v3CurPos;
float fRayRangeInv=1.0f/fRayRange;
while (fPos < fRayRange && fPos<fLimitRange)
{
D3DXVec3Lerp(&v3CurPos, &v3Start, &v3End, fPos*fRayRangeInv);
float fMultiplier = 1.0f;
if (rkMap.IsMapReady())
{
// PORT: PR_FLOAT_TO_INT is x87 fistp (round to nearest) corrected down, i.e. floor.
int ix = int(std::floor(v3CurPos.x)), iy = int(std::floor(fabs(v3CurPos.y)));
float fMapHeight = rkMap.GetHeight(float(ix), float(iy));
if ( fMapHeight >= v3CurPos.z)
{
*pv3Pick = v3CurPos;
return true;
}
else
{
fMultiplier = fMAX(1.0f, 0.01f * ( v3CurPos.z - fMapHeight ) );
}
}
fPos += fStep * fMultiplier;
}
return false;
}
}
// 40250 CMapOutdoor::GetPickingPointWithRayOnlyTerrain (MapOutdoor.cpp:549).
bool CPythonBackground::GetPickingPointWithRayOnlyTerrain(const CRay & rRay, D3DXVECTOR3 * v3IntersectPt)
{
bool bTerrainPick = false;
D3DXVECTOR3 v3TerrainPick;
D3DXVECTOR3 v3Start, v3End, v3Dir;
float fRayRange;
rRay.GetStartPoint(&v3Start);
rRay.GetDirection(&v3Dir, &fRayRange);
rRay.GetEndPoint(&v3End);
float fPos = 0.0f;
bTerrainPick=true;
if (!PickTerrainHeight(*this, fPos, v3Start, v3End, 5.0f, fRayRange, 5000.0f, &v3TerrainPick))
if (!PickTerrainHeight(*this, fPos, v3Start, v3End, 10.0f, fRayRange, 10000.0f, &v3TerrainPick))
if (!PickTerrainHeight(*this, fPos, v3Start, v3End, 100.0f, fRayRange, 100000.0f, &v3TerrainPick))
bTerrainPick=false;
if (bTerrainPick)
{
*v3IntersectPt = v3TerrainPick;
return true;
}
return false;
}
// 40250 CMapOutdoor::GetPickingPointWithRay (MapOutdoor.cpp:484).
// PORT: the object pick (FGetPickingPoint over CCullingManager) needs CMapOutdoor's area objects; only the
// terrain half runs until the map is ported.
bool CPythonBackground::GetPickingPointWithRay(const CRay & rRay, D3DXVECTOR3 * v3IntersectPt)
{
return GetPickingPointWithRayOnlyTerrain(rRay, v3IntersectPt);
}
// 40250 PythonBackground.cpp:173 (CPythonApplication::RenderGame's SetPerspective); m_pkMap stays null
// until the map is ported, so this is the 50000 far clip.
float CPythonBackground::GetFarClip()
{
if (!m_pkMap)
return 50000.0f;
if (m_ViewDistanceSet[m_eViewDistanceNum].m_fFarClip==0.0f)
{
TraceError("CPythonBackground::GetFarClip m_eViewDistanceNum=%d", m_eViewDistanceNum);
m_ViewDistanceSet[m_eViewDistanceNum].m_fFarClip=25600.0f;
}
return m_ViewDistanceSet[m_eViewDistanceNum].m_fFarClip;
}
auto CPythonBackground::Render() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderAfterLensFlare() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderBeforeLensFlare() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderCharacterShadowToTexture() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderCloud() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderEffect() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderPCBlocker() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderSky() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderSnow() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::RenderWater() -> void
{
MT_PLATFORM_STUB();
}
auto CPythonBackground::SetBackgroundDirLight() -> void
{
if (!IsMapReady() || !mc_pcurEnvironmentData)
return;
STATEMANAGER.SetLight(0, &mc_pcurEnvironmentData->DirLights[ENV_DIRLIGHT_BACKGROUND]);
}
auto CPythonBackground::SetCharacterDirLight() -> void
{
if (!IsMapReady() || !mc_pcurEnvironmentData)
return;
STATEMANAGER.SetLight(0, &mc_pcurEnvironmentData->DirLights[ENV_DIRLIGHT_CHARACTER]);
}
void CPythonBackground::Initialize()
{
std::string atlas(LocaleService_GetLocalePath());
atlas += "/AtlasInfo.txt";
SetAtlasInfoFileName(atlas.c_str());
CMapManager::Initialize();
}
// 40250 PythonBackground.cpp:263 → CMapOutdoor::GetPickingPoint (MapOutdoor.cpp:443): the cursor ray.
bool CPythonBackground::GetPickingPoint(D3DXVECTOR3 * v3IntersectPt)
{
return GetPickingPointWithRay(ms_Ray, v3IntersectPt);
}
@@ -21,3 +21,14 @@ auto CPythonSystem::IsShowDamage() -> bool
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CPythonSystem::GetShadowLevel() -> int
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<int>();
}
auto CPythonSystem::SetSoftwareTiling(bool isEnable) -> void
{
MT_PLATFORM_STUB();
}