Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API: Expose force vector and object axis display options #287

Merged
merged 4 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions OVP/D3D7Client/Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,13 @@ void Scene::Render ()
if (ptex) dev->SetTexture (0, 0);
if (!alpha) dev->SetRenderState (D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);

// render object vectors
if (*(DWORD*)gc->GetConfigParam(CFGPRM_FORCEVECTORFLAG) & BFV_ENABLE || *(DWORD*)gc->GetConfigParam(CFGPRM_FRAMEAXISFLAG) & FAV_ENABLE) {
cam->SetFrustumLimits(1.0, 1e30);
RenderVectors();
cam->SetFrustumLimits(npl, fpl);
}

// render the internal parts of the focus object in a separate render pass
if (oapiCameraInternal() && vFocus) {
// switch cockpit lights on, external-only lights off
Expand Down Expand Up @@ -632,6 +639,42 @@ void Scene::RenderObjectMarker (oapi::Sketchpad* pSkp, const VECTOR3 &gpos, cons
m_celSphere->RenderMarker(pSkp, dp, label1, label2, mode, scale);
}

// ==============================================================

void Scene::RenderVectors()
{
dev->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
dev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

dev->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, TRUE);
dev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT);
dev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_POINT);
dev->SetTexture(0, 0);
D3DMATERIAL7 pmtrl, mtrl = { {1,1,1,1},{1,1,1,1},{1,1,1,1},{0.2,0.2,0.2,1},40 };
dev->GetMaterial(&pmtrl);
dev->SetMaterial(&mtrl);

for (VOBJREC* pv = vobjFirst; pv; pv = pv->next) {
pv->vobj->RenderVectors(dev);
}

dev->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
dev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
dev->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE);
dev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
dev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR);
dev->SetMaterial(&pmtrl);
}

// ==============================================================

void Scene::NewVessel (OBJHANDLE hVessel)
{
CheckVisual (hVessel);
Expand Down
6 changes: 6 additions & 0 deletions OVP/D3D7Client/Scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ class Scene {
*/
void RenderObjectMarker (oapi::Sketchpad* pSkp, const VECTOR3 &gpos, const std::string& label1, const std::string& label2, int mode, int scale);

/**
* \brief Render vector features for each visual object if requested
* (frame axes, force vectors, etc.)
*/
void RenderVectors();

void AddLocalLight (const LightEmitter *le, const vObject *vo, DWORD idx);

private:
Expand Down
177 changes: 175 additions & 2 deletions OVP/D3D7Client/VObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "Camera.h"
#include "Texture.h"
#include "D3D7Util.h"
#include <algorithm>

using namespace oapi;

Expand Down Expand Up @@ -87,15 +88,20 @@ void vObject::Activate (bool isactive)
active = isactive;
}

bool veccomp(const vObject::BodyVectorRec& v1, const vObject::BodyVectorRec& v2)
{
return v1.dist > v2.dist; // sort from furthest to nearest
}

bool vObject::Update ()
{
if (!active) return false;

MATRIX3 grot;
oapiGetRotationMatrix (hObj, &grot);
oapiGetGlobalPos (hObj, &cpos);
cpos -= *scn->GetCamera()->GetGPos();
// object positions are relative to camera
cpos -= *scn->GetCamera()->GetGPos(); // global object position relative to camera
campos = tmul(grot, -cpos); // camera position in object frame

cdist = length (cpos);
// camera distance
Expand All @@ -109,9 +115,39 @@ bool vObject::Update ()
// update the object's world matrix

CheckResolution();
UpdateRenderVectors();
std::sort(veclist.begin(), veclist.end(), veccomp);

return true;
}

void vObject::UpdateRenderVectors()
{
veclist.clear();

// render object frame axes
DWORD flag = *(DWORD*)gc->GetConfigParam(CFGPRM_FRAMEAXISFLAG);
if (flag & FAV_ENABLE) {
int tp = oapiGetObjectType(hObj);
if ((tp == OBJTP_VESSEL && flag & FAV_VESSEL) ||
(tp == OBJTP_PLANET && flag & FAV_CELBODY) ||
(tp == OBJTP_SURFBASE && flag & FAV_BASE)) {

double scale = size * *(float*)gc->GetConfigParam(CFGPRM_FRAMEAXISSCALE);
double rad = size * 0.01;
float alpha = *(float*)gc->GetConfigParam(CFGPRM_FRAMEAXISOPACITY);
AddVector(_V(scale, 0, 0), _V(0, 0, 0), rad, std::string("+x"), _V(1, 1, 1), alpha, D3DRGB(1, 1, 1));
AddVector(_V(0, scale, 0), _V(0, 0, 0), rad, std::string("+y"), _V(1, 1, 1), alpha, D3DRGB(1, 1, 1));
AddVector(_V(0, 0, scale), _V(0, 0, 0), rad, std::string("+z"), _V(1, 1, 1), alpha, D3DRGB(1, 1, 1));
if (flag & FAV_NEGATIVE) {
AddVector(_V(-scale, 0, 0), _V(0, 0, 0), rad, std::string("-x"), _V(1, 1, 1), alpha, D3DRGB(1, 1, 1));
AddVector(_V(0, -scale, 0), _V(0, 0, 0), rad, std::string("-y"), _V(1, 1, 1), alpha, D3DRGB(1, 1, 1));
AddVector(_V(0, 0, -scale), _V(0, 0, 0), rad, std::string("-z"), _V(1, 1, 1), alpha, D3DRGB(1, 1, 1));
}
}
}
}

void vObject::RenderSpot (LPDIRECT3DDEVICE7 dev, const VECTOR3 *ofs, float size, const VECTOR3 &col, bool lighting, int shape)
{
static D3DMATRIX W = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1};
Expand Down Expand Up @@ -165,3 +201,140 @@ void vObject::RenderSpot (LPDIRECT3DDEVICE7 dev, const VECTOR3 *ofs, float size,
dev->SetTextureStageState (0, D3DTSS_COLOROP, D3DTOP_MODULATE);
dev->SetTextureStageState (0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
}

void vObject::AddVector(const VECTOR3& v, const VECTOR3& orig, double rad, const std::string& label, const VECTOR3& col, float alpha, DWORD lcol, float lsize)
{
double len = length(v);
if (len < 2.0 * rad) return; // too short to be rendered

VECTOR3 vu = v / len;
double dist = length(vu - campos); // distance of vector tip from camera

BodyVectorRec rec;
rec.v = v;
rec.orig = orig;
rec.rad = rad;
rec.dist = dist;
rec.col = col;
rec.alpha = alpha;
rec.label = label;
rec.lcol = lcol;
rec.lsize = lsize;

veclist.push_back(rec);
}

void vObject::RenderVectors(LPDIRECT3DDEVICE7 dev)
{
// Render and texture stage states are assumed to be set correctly on call

if (veclist.size()) {
float palpha = -1.0f;
VECTOR3 pcol = { -1,-1,-1 };
for (auto&& vec : veclist) {
if (vec.alpha != palpha || vec.col.x != pcol.x || vec.col.y != pcol.y || vec.col.z != pcol.z) {
dev->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, D3DRGBA(vec.col.x, vec.col.y, vec.col.z, vec.alpha));
palpha = vec.alpha; pcol = vec.col;
}
if (DrawVector(dev, vec.v, vec.orig, vec.rad) && vec.label.size()) {
double scale3 = (vec.lsize >= 0 ? vec.lsize : size);
//scene->Render3DLabel(mul(body->GRot(), ve->v + ve->v.unit() * (scale3 * 0.1)) + body->GPos(),
// ve->label, scale3, ve->lcol);
}
}
}
}

bool vObject::DrawVector(LPDIRECT3DDEVICE7 dev, const VECTOR3& end, const VECTOR3& orig, double rad)
{
static const float EPS = 1e-2f;
static const int nseg = 8;
static const int nVtx = nseg * 5;
static const int nIdx0 = nseg * 6 + nseg * 3;
static const int nIdx1 = nIdx0 + (nseg - 2) * 3;
int i, nIdx;
WORD* Idx;
static D3DVERTEX* Vtx0 = 0, * Vtx = 0;
static WORD* Idx0 = 0, * Idx1 = 0;
if (!Vtx0) { // create vector mesh template (pointing to +y)
int i0, i1;
Vtx0 = new D3DVERTEX[nVtx];
Vtx = new D3DVERTEX[nVtx];
Idx0 = new WORD[nIdx0];
Idx1 = new WORD[nIdx1];
for (i = 0; i < nseg; i++) {
Vtx0[i + 2 * nseg].x = Vtx0[i + 3 * nseg].x = 2.0f * (Vtx0[i].x = Vtx0[i + nseg].x = Vtx0[i].nx = Vtx0[i + nseg].nx = (float)cos(PI2 * (double)i / (double)nseg));
Vtx0[i + 2 * nseg].z = Vtx0[i + 3 * nseg].z = 2.0f * (Vtx0[i].z = Vtx0[i + nseg].z = Vtx0[i].nz = Vtx0[i + nseg].nz = (float)sin(PI2 * (double)i / (double)nseg));
Vtx0[i + 4 * nseg].x = Vtx0[i + 4 * nseg].z = 0.0f;
Vtx0[i].y = 0.0f; Vtx0[i + nseg].y = Vtx0[i + 2 * nseg].y = Vtx0[i + 3 * nseg].y = Vtx0[i + 4 * nseg].y = 1.0f;
Vtx0[i + 3 * nseg].nx = Vtx0[i + 4 * nseg].nx = (float)(0.894 * cos(PI2 * (double)(i + 0.5) / (double)nseg));
Vtx0[i + 3 * nseg].nz = Vtx0[i + 4 * nseg].nz = (float)(0.894 * sin(PI2 * (double)(i + 0.5) / (double)nseg));
Vtx0[i + 3 * nseg].ny = Vtx0[i + 4 * nseg].ny = 0.447f;
Vtx0[i].ny = Vtx0[i + nseg].ny = Vtx0[i + 2 * nseg].nx = Vtx0[i + 2 * nseg].nz = 0.0f;
Vtx0[i + 2 * nseg].ny = -1.0f;
}
for (i = i0 = 0, i1 = 6 * (nseg - 1); i < nseg; i++) { // stem
Idx0[i0++] = Idx1[i1++] = (WORD)i;
Idx0[i0++] = Idx1[i1++] = (WORD)(i + nseg);
Idx0[i0++] = Idx1[i1++] = (WORD)((i + 1) % nseg + nseg);
Idx0[i0++] = Idx1[i1++] = (WORD)i;
Idx0[i0++] = Idx1[i1++] = (WORD)((i + 1) % nseg + nseg);
Idx0[i0++] = Idx1[i1++] = (WORD)((i + 1) % nseg);
}
for (i = 0, i1 = nseg * 3; i < nseg - 2; i++) { // tip base
Idx1[i1++] = nseg * 2;
Idx1[i1++] = nseg * 2 + 1 + i;
Idx1[i1++] = nseg * 2 + 2 + i;
}
for (i = i1 = 0, i0 = nseg * 6; i < nseg; i++) { // tip
Idx0[i0++] = Idx1[i1++] = nseg * 3 + i;
Idx0[i0++] = Idx1[i1++] = nseg * 4 + i;
Idx0[i0++] = Idx1[i1++] = 3 * nseg + (i + 1) % nseg;
}
}

float w = (float)rad;
float h = (float)length(end);
if (h < EPS) return false;
float hb = max(h - 4.0f * w, 0);

memcpy(Vtx, Vtx0, nVtx * sizeof(D3DVERTEX));

for (i = 0; i < nseg; i++) {
Vtx[i + 3 * nseg].y = Vtx[i + 2 * nseg].y = Vtx[i + nseg].y = hb;
Vtx[i + 4 * nseg].y = h;
Vtx[i].x = Vtx[i + nseg].x *= w, Vtx[i].z = Vtx[i + nseg].z *= w;
Vtx[i + 3 * nseg].x = Vtx[i + 2 * nseg].x *= w, Vtx[i + 3 * nseg].z = Vtx[i + 2 * nseg].z *= w;
}

// rotate vector
VECTOR3 d = end / h;
double tht = acos(d.y), phi = atan2(d.z, d.x);
float cost = (float)cos(tht), sint = (float)sin(tht);
float cosp = (float)cos(phi), sinp = (float)sin(phi);
D3DMATRIX W, R = { cost * cosp, -sint, cost * sinp, 0,
sint * cosp, cost, sint * sinp, 0,
-sinp, 0 , cosp, 0,
0, 0, 0, 1 };

// shift vector
R._41 = (float)orig.x;
R._42 = (float)orig.y;
R._43 = (float)orig.z;
D3DMAT_MatrixMultiply(&W, &mWorld, &R);
dev->SetTransform(D3DTRANSFORMSTATE_WORLD, &W);

MATRIX3 grot;
VECTOR3 gpos;
oapiGetRotationMatrix(hObj, &grot);
VECTOR3 cp = tmul(grot, -cpos);
if (dotp(d, unit(end - cp)) > 0)
Idx = Idx1, nIdx = nIdx1;
else
Idx = Idx0, nIdx = nIdx0;

dev->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST, D3DFVF_VERTEX, Vtx, nVtx, Idx, nIdx, 0);
dev->SetTransform(D3DTRANSFORMSTATE_WORLD, &mWorld);
return true;
}
35 changes: 34 additions & 1 deletion OVP/D3D7Client/VObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,16 @@ class vObject: public oapi::VisObject {
*/
virtual bool Update ();

/**
* \brief Set up any vectors (forces, coordinate axes) to be drawn in the
* next render pass.
*
* Resets the vector list and adds object frame axes if requested for the
* given object type. Derived classes should extend this to add their own
* vector displays.
*/
virtual void UpdateRenderVectors();

/**
* \brief Level-of-detail check
* \default None.
Expand Down Expand Up @@ -167,9 +177,30 @@ class vObject: public oapi::VisObject {
*/
virtual void RenderBeacons (LPDIRECT3DDEVICE7 dev) {}

/**
* \brief structure for rendering vectors
*/
struct BodyVectorRec {
VECTOR3 v; ///< vector definition in local object frame
VECTOR3 orig; ///< vector origin in local object frame
double rad; ///< vector arrow radius
double dist; ///< camera distance
VECTOR3 col; ///< colour components
float alpha; ///< alpha component
std::string label; ///< vector label
DWORD lcol;
float lsize; ///< length scale
};

virtual void RenderVectors(LPDIRECT3DDEVICE7 dev);

protected:
void RenderSpot (LPDIRECT3DDEVICE7 dev, const VECTOR3 *ofs, float size, const VECTOR3 &col, bool lighting, int shape);

void AddVector(const VECTOR3& v, const VECTOR3& orig, double rad, const std::string& label, const VECTOR3& col, float alpha = 1.0f, DWORD lcol = 0, float lsize = -1.0);

bool DrawVector(LPDIRECT3DDEVICE7 dev, const VECTOR3& end, const VECTOR3& orig, double rad);

static const oapi::D3D7Client *gc; // graphics client instance pointer
static LPDIRECTDRAWSURFACE7 blobtex[3]; // beacon textures

Expand All @@ -180,7 +211,9 @@ class vObject: public oapi::VisObject {
MATRIX4 dmWorld; // world matrix in double precision
double size; // object radius [m]
double cdist; // current camera distance
VECTOR3 cpos; // camera-relative object position
VECTOR3 cpos; // camera-relative object position in global frame
VECTOR3 campos; // camera position in object frame
std::vector<BodyVectorRec> veclist; ///< list of body vectors to be rendered
};

#endif // !__VOBJECT_H
Loading