mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 16:18:19 -10:00
* Add global to local for matrices * Add lua integration * Get Submodel from Submodel instance * Add submodel functions * Add model instance from submodel instance * Fix index * Fix copy paste error
402 lines
14 KiB
C++
402 lines
14 KiB
C++
//
|
|
//
|
|
|
|
#include "model.h"
|
|
#include "modelinstance.h"
|
|
#include "object.h"
|
|
#include "vecmath.h"
|
|
|
|
namespace scripting {
|
|
namespace api {
|
|
|
|
ADE_OBJ(l_ModelInstance, modelinstance_h, "model_instance", "Model instance handle");
|
|
|
|
modelinstance_h::modelinstance_h(int pmi_id)
|
|
{
|
|
_pmi = model_get_instance(pmi_id);
|
|
}
|
|
modelinstance_h::modelinstance_h(polymodel_instance *pmi)
|
|
: _pmi(pmi)
|
|
{}
|
|
modelinstance_h::modelinstance_h()
|
|
: _pmi(nullptr)
|
|
{}
|
|
polymodel_instance *modelinstance_h::Get()
|
|
{
|
|
return _pmi;
|
|
}
|
|
bool modelinstance_h::IsValid()
|
|
{
|
|
return (_pmi != nullptr);
|
|
}
|
|
|
|
|
|
ADE_OBJ(l_SubmodelInstance, submodelinstance_h, "submodel_instance", "Submodel instance handle");
|
|
|
|
submodelinstance_h::submodelinstance_h(int pmi_id, int submodel_num)
|
|
: _submodel_num(submodel_num)
|
|
{
|
|
_pmi = model_get_instance(pmi_id);
|
|
_pm = _pmi ? model_get(_pmi->model_num) : nullptr;
|
|
}
|
|
submodelinstance_h::submodelinstance_h(polymodel_instance *pmi, int submodel_num)
|
|
: _pmi(pmi), _submodel_num(submodel_num)
|
|
{
|
|
_pm = pmi ? model_get(pmi->model_num) : nullptr;
|
|
}
|
|
submodelinstance_h::submodelinstance_h()
|
|
: _pmi(nullptr), _pm(nullptr), _submodel_num(-1)
|
|
{}
|
|
polymodel_instance *submodelinstance_h::GetModelInstance()
|
|
{
|
|
return IsValid() ? _pmi : nullptr;
|
|
}
|
|
submodel_instance *submodelinstance_h::Get()
|
|
{
|
|
return IsValid() ? &_pmi->submodel[_submodel_num] : nullptr;
|
|
}
|
|
polymodel *submodelinstance_h::GetModel()
|
|
{
|
|
return IsValid() ? _pm : nullptr;
|
|
}
|
|
bsp_info *submodelinstance_h::GetSubmodel()
|
|
{
|
|
return IsValid() ? &_pm->submodel[_submodel_num] : nullptr;
|
|
}
|
|
int submodelinstance_h::GetSubmodelIndex()
|
|
{
|
|
return IsValid() ? _submodel_num : -1;
|
|
}
|
|
bool submodelinstance_h::IsValid()
|
|
{
|
|
return _pmi != nullptr && _pm != nullptr && _submodel_num >= 0 && _submodel_num < _pm->n_models;
|
|
}
|
|
|
|
|
|
ADE_FUNC(getModel, l_ModelInstance, nullptr, "Returns the model used by this instance", "model", "A model")
|
|
{
|
|
modelinstance_h *mih;
|
|
if (!ade_get_args(L, "o", l_ModelInstance.GetPtr(&mih)))
|
|
return ade_set_error(L, "o", l_Model.Set(model_h()));
|
|
|
|
return ade_set_args(L, "o", l_Model.Set(model_h(mih->Get()->model_num)));
|
|
}
|
|
|
|
ADE_FUNC(getObject, l_ModelInstance, nullptr, "Returns the object that this instance refers to", "object", "An object")
|
|
{
|
|
modelinstance_h *mih;
|
|
if (!ade_get_args(L, "o", l_ModelInstance.GetPtr(&mih)))
|
|
return ade_set_error(L, "o", l_Object.Set(object_h()));
|
|
|
|
if (mih->Get()->objnum < 0)
|
|
return ade_set_error(L, "o", l_Object.Set(object_h()));
|
|
|
|
return ade_set_object_with_breed(L, mih->Get()->objnum);
|
|
}
|
|
|
|
ADE_VIRTVAR(SubmodelInstances, l_ModelInstance, nullptr, "Submodel instances", "submodel_instances", "Model submodel instances, or an invalid modelsubmodelinstances handle if the model instance handle is invalid")
|
|
{
|
|
modelinstance_h *mih = nullptr;
|
|
if (!ade_get_args(L, "o", l_ModelInstance.GetPtr(&mih)))
|
|
return ade_set_error(L, "o", l_ModelSubmodelInstances.Set(modelsubmodelinstances_h()));
|
|
|
|
auto pmi = mih->Get();
|
|
if (!pmi)
|
|
return ade_set_error(L, "o", l_ModelSubmodelInstances.Set(modelsubmodelinstances_h()));
|
|
|
|
if (ADE_SETTING_VAR)
|
|
LuaError(L, "Attempt to use Incomplete Feature: submodel instance copy");
|
|
|
|
return ade_set_args(L, "o", l_ModelSubmodelInstances.Set(modelsubmodelinstances_h(pmi)));
|
|
}
|
|
|
|
ADE_FUNC(isValid, l_ModelInstance, nullptr, "True if valid, false or nil if not", "boolean", "Detects whether handle is valid")
|
|
{
|
|
modelinstance_h *mih;
|
|
if (!ade_get_args(L, "o", l_ModelInstance.GetPtr(&mih)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
return ade_set_args(L, "b", mih->IsValid());
|
|
}
|
|
|
|
ADE_FUNC(getModelInstance, l_SubmodelInstance, nullptr, "Gets the model instance of this submodel", "model_instance", "A model instancve")
|
|
{
|
|
submodelinstance_h* smih;
|
|
if (!ade_get_args(L, "o", l_SubmodelInstance.GetPtr(&smih)))
|
|
return ade_set_error(L, "o", l_ModelInstance.Set(modelinstance_h()));
|
|
|
|
if (!smih->IsValid())
|
|
return ade_set_error(L, "o", l_ModelInstance.Set(modelinstance_h()));
|
|
|
|
return ade_set_args(L, "o", l_ModelInstance.Set(modelinstance_h(smih->GetModelInstance())));
|
|
}
|
|
|
|
ADE_FUNC(getSubmodel, l_SubmodelInstance, nullptr, "Gets the submodel of this instance", "submodel", "A submodel")
|
|
{
|
|
submodelinstance_h* smih;
|
|
if (!ade_get_args(L, "o", l_SubmodelInstance.GetPtr(&smih)))
|
|
return ade_set_error(L, "o", l_Submodel.Set(submodel_h()));
|
|
|
|
if (!smih->IsValid())
|
|
return ade_set_error(L, "o", l_Submodel.Set(submodel_h()));
|
|
|
|
return ade_set_args(L, "o", l_Submodel.Set(submodel_h(smih->GetModel(), smih->GetSubmodelIndex())));
|
|
}
|
|
|
|
ADE_VIRTVAR(Orientation, l_SubmodelInstance, "orientation", "Gets or sets the submodel instance orientation", "orientation", "Orientation, or identity orientation if handle is not valid")
|
|
{
|
|
submodelinstance_h *smih;
|
|
matrix_h *mh = nullptr;
|
|
if (!ade_get_args(L, "o|o", l_SubmodelInstance.GetPtr(&smih), l_Matrix.GetPtr(&mh)))
|
|
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
|
|
|
|
if (!smih->IsValid())
|
|
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
|
|
|
|
auto smi = smih->Get();
|
|
if (smi == nullptr)
|
|
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
|
|
|
|
if (ADE_SETTING_VAR && mh != nullptr)
|
|
{
|
|
smi->canonical_prev_orient = smi->canonical_orient;
|
|
smi->canonical_orient = *mh->GetMatrix();
|
|
|
|
float angle = 0.0f;
|
|
vm_closest_angle_to_matrix(&smi->canonical_orient, &smih->GetSubmodel()->rotation_axis, &angle);
|
|
|
|
smi->cur_angle = angle;
|
|
smi->turret_idle_angle = angle;
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&smi->canonical_orient)));
|
|
}
|
|
|
|
ADE_VIRTVAR(TranslationOffset,
|
|
l_SubmodelInstance,
|
|
"vector",
|
|
"Gets or sets the translated submodel instance offset. This is relative to the existing submodel offset to its parent; a non-translated submodel will have a TranslationOffset of zero.",
|
|
"vector",
|
|
"Offset, or zero vector if handle is not valid")
|
|
{
|
|
submodelinstance_h *smih;
|
|
vec3d *vec = nullptr;
|
|
if (!ade_get_args(L, "o|o", l_SubmodelInstance.GetPtr(&smih), l_Vector.GetPtr(&vec)))
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (!smih->IsValid())
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (ADE_SETTING_VAR && vec != nullptr)
|
|
{
|
|
auto smi = smih->Get();
|
|
|
|
smi->canonical_prev_offset = smi->canonical_offset;
|
|
smi->canonical_offset = *vec;
|
|
|
|
smi->cur_offset = vm_vec_mag(vec);
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Vector.Set(smih->Get()->canonical_offset));
|
|
}
|
|
|
|
ADE_FUNC(findWorldPoint, l_SubmodelInstance, "vector", "Calculates the world coordinates of a point in a submodel's frame of reference", "vector", "Point, or empty vector if handle is not valid")
|
|
{
|
|
submodelinstance_h *smih;
|
|
vec3d pnt, outpnt;
|
|
if (!ade_get_args(L, "oo", l_SubmodelInstance.GetPtr(&smih), l_Vector.Get(&pnt)))
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (!smih->IsValid())
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
auto pmi = smih->GetModelInstance();
|
|
if (pmi->objnum < 0)
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
auto objp = &Objects[pmi->objnum];
|
|
|
|
model_instance_local_to_global_point(&outpnt, &pnt, pmi->id, smih->GetSubmodelIndex(), &objp->orient, &objp->pos);
|
|
return ade_set_args(L, "o", l_Vector.Set(outpnt));
|
|
}
|
|
|
|
ADE_FUNC(findWorldDir, l_SubmodelInstance, "vector", "Calculates the world direction of a vector in a submodel's frame of reference", "vector", "Vector, or empty vector if handle is not valid")
|
|
{
|
|
submodelinstance_h *smih;
|
|
vec3d dir, outdir;
|
|
if (!ade_get_args(L, "oo", l_SubmodelInstance.GetPtr(&smih), l_Vector.Get(&dir)))
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
if (!smih->IsValid())
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
|
|
auto pmi = smih->GetModelInstance();
|
|
if (pmi->objnum < 0)
|
|
return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
|
|
auto objp = &Objects[pmi->objnum];
|
|
|
|
model_instance_local_to_global_dir(&outdir, &dir, smih->GetModel(), pmi, smih->GetSubmodelIndex(), &objp->orient);
|
|
return ade_set_args(L, "o", l_Vector.Set(outdir));
|
|
}
|
|
|
|
bool findObjectPointAndOrientationSub(lua_State *L, bool use_object, vec3d *outpnt, matrix *outorient)
|
|
{
|
|
submodelinstance_h *smih;
|
|
vec3d local_pnt;
|
|
matrix_h *local_orient;
|
|
if (!ade_get_args(L, "ooo", l_SubmodelInstance.GetPtr(&smih), l_Vector.Get(&local_pnt), l_Matrix.GetPtr(&local_orient)))
|
|
return false;
|
|
|
|
if (!smih->IsValid())
|
|
return false;
|
|
|
|
auto pmi = smih->GetModelInstance();
|
|
if (pmi->objnum < 0)
|
|
return false;
|
|
auto objp = &Objects[pmi->objnum];
|
|
|
|
model_instance_local_to_global_point_orient(outpnt, outorient, &local_pnt, local_orient->GetMatrix(), smih->GetModel(), pmi, smih->GetSubmodelIndex(), use_object ? &objp->orient : nullptr, use_object ? &objp->pos : nullptr);
|
|
return true;
|
|
}
|
|
|
|
ADE_FUNC(findObjectPointAndOrientation, l_SubmodelInstance, "vector, orientation", "Calculates the coordinates and orientation, in an object's frame of reference, of a point and orientation in a submodel's frame of reference", "vector, orientation", "Vector and orientation, or empty values if a handle is invalid")
|
|
{
|
|
vec3d pnt;
|
|
matrix orient;
|
|
|
|
if (!findObjectPointAndOrientationSub(L, false, &pnt, &orient))
|
|
return ade_set_error(L, "oo", l_Vector.Set(vmd_zero_vector), l_Matrix.Set(matrix_h(&vmd_zero_matrix)));
|
|
|
|
return ade_set_args(L, "oo", l_Vector.Set(pnt), l_Matrix.Set(matrix_h(&orient)));
|
|
}
|
|
|
|
ADE_FUNC(findWorldPointAndOrientation, l_SubmodelInstance, "vector, orientation", "Calculates the world coordinates and orientation of a point and orientation in a submodel's frame of reference", "vector, orientation", "Vector and orientation, or empty values if a handle is invalid")
|
|
{
|
|
vec3d pnt;
|
|
matrix orient;
|
|
|
|
if (!findObjectPointAndOrientationSub(L, true, &pnt, &orient))
|
|
return ade_set_error(L, "oo", l_Vector.Set(vmd_zero_vector), l_Matrix.Set(matrix_h(&vmd_zero_matrix)));
|
|
|
|
return ade_set_args(L, "oo", l_Vector.Set(pnt), l_Matrix.Set(matrix_h(&orient)));
|
|
}
|
|
|
|
ADE_FUNC(findLocalPointAndOrientation, l_SubmodelInstance, "vector, orientation, [boolean world = true]", "Calculates the coordinates and orientation in the submodel's frame of reference, of a point and orientation in world coordinates [world = true] / in the object's frame of reference [world = false]", "vector, orientation", "Vector and orientation, or empty values if a handle is invalid")
|
|
{
|
|
vec3d local_pnt;
|
|
matrix local_orient;
|
|
|
|
submodelinstance_h* smih;
|
|
vec3d global_pnt;
|
|
matrix_h* global_orient;
|
|
bool fromWorld = true;
|
|
|
|
if (!ade_get_args(L, "ooo|b", l_SubmodelInstance.GetPtr(&smih), l_Vector.Get(&global_pnt), l_Matrix.GetPtr(&global_orient), &fromWorld))
|
|
return ade_set_error(L, "oo", l_Vector.Set(vmd_zero_vector), l_Matrix.Set(matrix_h(&vmd_zero_matrix)));
|
|
|
|
if (!smih->IsValid())
|
|
return ade_set_error(L, "oo", l_Vector.Set(vmd_zero_vector), l_Matrix.Set(matrix_h(&vmd_zero_matrix)));
|
|
|
|
auto pmi = smih->GetModelInstance();
|
|
if (fromWorld && pmi->objnum < 0)
|
|
return ade_set_error(L, "oo", l_Vector.Set(vmd_zero_vector), l_Matrix.Set(matrix_h(&vmd_zero_matrix)));
|
|
|
|
model_instance_global_to_local_point_orient(&local_pnt, &local_orient, &global_pnt, global_orient->GetMatrix(), smih->GetModel(), pmi, smih->GetSubmodelIndex(), fromWorld ? &Objects[pmi->objnum].orient : nullptr, fromWorld ? &Objects[pmi->objnum].pos : nullptr);
|
|
|
|
return ade_set_args(L, "oo", l_Vector.Set(local_pnt), l_Matrix.Set(matrix_h(&local_orient)));
|
|
}
|
|
|
|
ADE_FUNC(isValid, l_SubmodelInstance, nullptr, "True if valid, false or nil if not", "boolean", "Detects whether handle is valid")
|
|
{
|
|
submodelinstance_h *smih;
|
|
if (!ade_get_args(L, "o", l_SubmodelInstance.GetPtr(&smih)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
return ade_set_args(L, "b", smih->IsValid());
|
|
}
|
|
|
|
|
|
ADE_OBJ(l_ModelSubmodelInstances, modelsubmodelinstances_h, "submodel_instances", "Array of submodel instances");
|
|
|
|
modelsubmodelinstances_h::modelsubmodelinstances_h(polymodel_instance *pmi) : modelinstance_h(pmi){}
|
|
modelsubmodelinstances_h::modelsubmodelinstances_h() : modelinstance_h(){}
|
|
|
|
ADE_FUNC(__len, l_ModelSubmodelInstances, nullptr, "Number of submodel instances on model", "number", "Number of model submodel instances")
|
|
{
|
|
modelsubmodelinstances_h *msih;
|
|
if (!ade_get_args(L, "o", l_ModelSubmodelInstances.GetPtr(&msih)))
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
if (!msih->IsValid())
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
auto pmi = msih->Get();
|
|
if (!pmi)
|
|
return ade_set_error(L, "i", 0);
|
|
auto pm = model_get(pmi->model_num);
|
|
if (!pm)
|
|
return ade_set_error(L, "i", 0);
|
|
|
|
return ade_set_args(L, "i", pm->n_models);
|
|
}
|
|
|
|
ADE_INDEXER(l_ModelSubmodelInstances, "submodel_instance", "number|string IndexOrName", "submodel_instance", "Model submodel instances, or invalid modelsubmodelinstances handle if model instance handle is invalid")
|
|
{
|
|
modelsubmodelinstances_h *msih = nullptr;
|
|
int index = -1;
|
|
|
|
if (lua_isnumber(L, 2))
|
|
{
|
|
if (!ade_get_args(L, "oi", l_ModelSubmodelInstances.GetPtr(&msih), &index))
|
|
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
|
|
|
|
if (!msih->IsValid())
|
|
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
|
|
|
|
index--; // Lua --> C/C++
|
|
}
|
|
else if (lua_isstring(L, 2))
|
|
{
|
|
const char *name = nullptr;
|
|
|
|
if (!ade_get_args(L, "os", l_ModelSubmodelInstances.GetPtr(&msih), &name))
|
|
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
|
|
|
|
if (!msih->IsValid() || name == nullptr)
|
|
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
|
|
|
|
index = model_find_submodel_index(msih->Get()->model_num, name);
|
|
}
|
|
else
|
|
{
|
|
submodel_h *smh;
|
|
|
|
if (!ade_get_args(L, "oo", l_ModelSubmodelInstances.GetPtr(&msih), l_Submodel.GetPtr(&smh)))
|
|
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
|
|
|
|
if (!msih->IsValid() || !smh->IsValid())
|
|
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
|
|
|
|
index = smh->GetSubmodelIndex();
|
|
}
|
|
|
|
auto pmi = msih->Get();
|
|
auto pm = model_get(pmi->model_num);
|
|
|
|
if (index < 0 || index >= pm->n_models)
|
|
return ade_set_error(L, "o", l_SubmodelInstance.Set(submodelinstance_h()));
|
|
|
|
return ade_set_args(L, "o", l_SubmodelInstance.Set(submodelinstance_h(pmi, index)));
|
|
}
|
|
|
|
ADE_FUNC(isValid, l_ModelSubmodelInstances, nullptr, "Detects whether handle is valid", "boolean", "true if valid, false if invalid, nil if a syntax/type error occurs")
|
|
{
|
|
modelsubmodelinstances_h *msih;
|
|
if (!ade_get_args(L, "o", l_ModelSubmodelInstances.GetPtr(&msih)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
return ade_set_args(L, "b", msih->IsValid());
|
|
}
|
|
|
|
}
|
|
}
|