Files
metin2-client/src/port/UserInterface/PythonRenderTargetModule.cpp
T
shenleiandClaude Opus 5.5 84404cf1f1 Model preview: AVA2 render-target window on a Vulkan colour target
Port of AVA2's CRenderTarget / GrpRenderTargetTexture / renderTarget module.
The host gains an RGBA8 offscreen colour pass for D3D colour render targets;
mt_preview shows wearable items on every allowed race and monsters with
motions, reached by X+click in the inventory and shop and from the wiki.
Player races are created as TYPE_PC so their parts exist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 04:48:07 +09:00

283 lines
8.5 KiB
C++

// PORT: AVA2 CPythonRenderTargetModule (module renderTarget), the subset the model preview uses. AVA2's window
// manager created the target for a registered window and drew it; here Create and RenderTexture do that, called
// from the script's own window (ScriptLib/ModelPreviewScript.inc).
#include "StdAfx.h"
#include "CRenderTargetManager.h"
#include "InstanceBase.h"
#include "../GameLib/ItemManager.h"
namespace
{
// The default of CPythonApplication's camera zoom speed (PythonApplicationCamera.cpp), which AVA2 read.
const float c_fRenderTargetZoomSpeed = 0.05f;
std::shared_ptr<CRenderTarget> Target(PyObject* poArgs)
{
int iIndex;
if (!PyTuple_GetInteger(poArgs, 0, &iIndex))
return nullptr;
return CRenderTargetManager::Instance().GetRenderTarget(iIndex);
}
bool Integer(PyObject* poArgs, int pos, int* value)
{
return PyTuple_GetInteger(poArgs, pos, value);
}
}
PyObject* renderTargetCreate(PyObject* poSelf, PyObject* poArgs)
{
int iIndex, iWidth, iHeight;
if (!Integer(poArgs, 0, &iIndex) || !Integer(poArgs, 1, &iWidth) || !Integer(poArgs, 2, &iHeight))
return Py_BadArgument();
return Py_BuildValue("i", CRenderTargetManager::Instance().CreateRenderTarget(iIndex, iWidth, iHeight) ? 1 : 0);
}
PyObject* renderTargetRemove(PyObject* poSelf, PyObject* poArgs)
{
int iIndex;
if (!Integer(poArgs, 0, &iIndex))
return Py_BadArgument();
CRenderTargetManager::Instance().RemoveRenderTarget(iIndex);
return Py_BuildNone();
}
PyObject* renderTargetExists(PyObject* poSelf, PyObject* poArgs)
{
int iIndex;
if (!Integer(poArgs, 0, &iIndex))
return Py_BadArgument();
return Py_BuildValue("i", CRenderTargetManager::Instance().GetRenderTarget(iIndex) ? 1 : 0);
}
PyObject* renderTargetRenderTexture(PyObject* poSelf, PyObject* poArgs)
{
int l, t, r, b;
if (!Integer(poArgs, 1, &l) || !Integer(poArgs, 2, &t) || !Integer(poArgs, 3, &r) || !Integer(poArgs, 4, &b))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target && target->IsShow())
{
RECT rect = { l, t, r, b };
target->SetRenderingRect(&rect);
target->RenderTexture();
}
return Py_BuildNone();
}
PyObject* renderTargetSelectModel(PyObject* poSelf, PyObject* poArgs)
{
int modelIndex;
if (!Integer(poArgs, 1, &modelIndex))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target)
target->SelectModel(modelIndex);
return Py_BuildValue("i", target && target->GetModel() ? 1 : 0);
}
PyObject* renderTargetSetArmor(PyObject* poSelf, PyObject* poArgs)
{
int iItemVnum;
if (!Integer(poArgs, 1, &iItemVnum))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target && target->IsReady())
target->GetModel()->ChangeArmor(iItemVnum);
return Py_BuildNone();
}
PyObject* renderTargetSetWeapon(PyObject* poSelf, PyObject* poArgs)
{
int iItemVnum;
if (!Integer(poArgs, 1, &iItemVnum))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target && target->IsReady())
target->GetModel()->ChangeWeapon(iItemVnum);
return Py_BuildNone();
}
PyObject* renderTargetSetHair(PyObject* poSelf, PyObject* poArgs)
{
int iItemVnum;
if (!Integer(poArgs, 1, &iItemVnum))
return Py_BadArgument();
bool isValue = false;
const auto target = Target(poArgs);
if (target)
{
PyTuple_GetBoolean(poArgs, 2, &isValue);
if (!isValue)
{
CItemData* pItemData;
if (!CItemManager::Instance().GetItemDataPointer(iItemVnum, &pItemData))
return Py_BuildNone();
iItemVnum = pItemData->GetValue(3);
}
if (target->IsReady())
target->GetModel()->SetHair(iItemVnum);
}
return Py_BuildNone();
}
PyObject* renderTargetSetMount(PyObject* poSelf, PyObject* poArgs)
{
int iRace;
if (!Integer(poArgs, 1, &iRace))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target && target->IsReady())
target->GetModel()->MountHorse(iRace);
return Py_BuildNone();
}
PyObject* renderTargetSetRotation(PyObject* poSelf, PyObject* poArgs)
{
bool bRot;
if (!PyTuple_GetBoolean(poArgs, 1, &bRot))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target)
target->SetRotation(bRot);
return Py_BuildNone();
}
PyObject* renderTargetSetVisibility(PyObject* poSelf, PyObject* poArgs)
{
bool isShow;
if (!PyTuple_GetBoolean(poArgs, 1, &isShow))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target)
target->SetVisibility(isShow);
return Py_BuildNone();
}
PyObject* renderTargetSetBackground(PyObject* poSelf, PyObject* poArgs)
{
char* szPathName;
if (!PyTuple_GetString(poArgs, 1, &szPathName))
return Py_BadArgument();
const auto target = Target(poArgs);
// PORT: the background is stretched over the target when drawn, so the sizes AVA2 passed are unused.
return Py_BuildValue("i", target && target->CreateBackground(szPathName, 0, 0) ? 1 : 0);
}
PyObject* renderTargetResetModel(PyObject* poSelf, PyObject* poArgs)
{
const auto target = Target(poArgs);
if (target)
target->ResetModel();
return Py_BuildNone();
}
PyObject* renderTargetDestroy(PyObject* poSelf, PyObject* poArgs)
{
CRenderTargetManager::Instance().Destroy();
return Py_BuildNone();
}
PyObject* renderTargetSetModelV3Eye(PyObject* poSelf, PyObject* poArgs)
{
float x, y, z;
if (!PyTuple_GetFloat(poArgs, 1, &x) || !PyTuple_GetFloat(poArgs, 2, &y) || !PyTuple_GetFloat(poArgs, 3, &z))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target)
target->SetModelV3Eye(x, y, z);
return Py_BuildNone();
}
PyObject* renderTargetSetModelV3Target(PyObject* poSelf, PyObject* poArgs)
{
float x, y, z;
if (!PyTuple_GetFloat(poArgs, 1, &x) || !PyTuple_GetFloat(poArgs, 2, &y) || !PyTuple_GetFloat(poArgs, 3, &z))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target)
target->SetModelV3Target(x, y, z);
return Py_BuildNone();
}
PyObject* renderTargetZoom(PyObject* poSelf, PyObject* poArgs)
{
int iDirection;
if (!Integer(poArgs, 1, &iDirection))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target && target->IsReady())
target->Zoom(1.0f + c_fRenderTargetZoomSpeed * float(iDirection));
return Py_BuildNone();
}
PyObject* renderTargetRotateEyeAroundTarget(PyObject* poSelf, PyObject* poArgs)
{
float fPitch, fRoll;
if (!PyTuple_GetFloat(poArgs, 1, &fPitch) || !PyTuple_GetFloat(poArgs, 2, &fRoll))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target && target->IsReady())
target->RotateEyeAroundTarget(fPitch, fRoll);
return Py_BuildNone();
}
PyObject* renderTargetSetScale(PyObject* poSelf, PyObject* poArgs)
{
float fScale;
if (!PyTuple_GetFloat(poArgs, 1, &fScale))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target)
target->SetScale(fScale);
return Py_BuildNone();
}
PyObject* renderTargetIsShow(PyObject* poSelf, PyObject* poArgs)
{
const auto target = Target(poArgs);
return Py_BuildValue("i", target ? target->IsShow() : 0);
}
PyObject* renderTargetSetMotionIndex(PyObject* poSelf, PyObject* poArgs)
{
int iMotionIndex;
if (!Integer(poArgs, 1, &iMotionIndex))
return Py_BadArgument();
const auto target = Target(poArgs);
if (target && target->IsReady())
return Py_BuildValue("i", target->GetModel()->GetGraphicThingInstanceRef().InterceptOnceMotion(iMotionIndex) ? 1 : 0);
return Py_BuildValue("i", 0);
}
void initRenderTarget()
{
static PyMethodDef s_methods[] =
{
{ "Create", renderTargetCreate, METH_VARARGS },
{ "Remove", renderTargetRemove, METH_VARARGS },
{ "Exists", renderTargetExists, METH_VARARGS },
{ "RenderTexture", renderTargetRenderTexture, METH_VARARGS },
{ "SelectModel", renderTargetSelectModel, METH_VARARGS },
{ "SetVisibility", renderTargetSetVisibility, METH_VARARGS },
{ "SetBackground", renderTargetSetBackground, METH_VARARGS },
{ "SetArmor", renderTargetSetArmor, METH_VARARGS },
{ "SetWeapon", renderTargetSetWeapon, METH_VARARGS },
{ "SetHair", renderTargetSetHair, METH_VARARGS },
{ "SetMount", renderTargetSetMount, METH_VARARGS },
{ "SetRotation", renderTargetSetRotation, METH_VARARGS },
{ "ResetModel", renderTargetResetModel, METH_VARARGS },
{ "Destroy", renderTargetDestroy, METH_VARARGS },
{ "SetModelV3Eye", renderTargetSetModelV3Eye, METH_VARARGS },
{ "SetModelV3Target", renderTargetSetModelV3Target, METH_VARARGS },
{ "Zoom", renderTargetZoom, METH_VARARGS },
{ "RotateEyeAroundTarget", renderTargetRotateEyeAroundTarget, METH_VARARGS },
{ "SetScale", renderTargetSetScale, METH_VARARGS },
{ "IsShow", renderTargetIsShow, METH_VARARGS },
{ "SetMotionIndex", renderTargetSetMotionIndex, METH_VARARGS },
{ NULL, NULL, 0 },
};
Py_InitModule("renderTarget", s_methods);
}