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>
283 lines
8.5 KiB
C++
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);
|
|
}
|