Store the status of the scene in the scene itself.

PiperOrigin-RevId: 813119377
Change-Id: Iebff9e7796ca9809ea22902522982bfd96eeba06
This commit is contained in:
Haroon Qureshi
2025-09-30 00:05:06 -07:00
committed by Copybara-Service
parent fc8979ed4a
commit 70d03adc71
7 changed files with 69 additions and 53 deletions
+1
View File
@@ -2948,6 +2948,7 @@ struct mjvScene_ { // abstract scene passed to OpenGL renderer
// framing
int framewidth; // frame pixel width; 0: disable framing
float framergb[3]; // frame color
int status; // status; 0: ok, 1: geoms exhausted
};
typedef struct mjvScene_ mjvScene;
struct mjvFigure_ { // abstract 2D figure passed to OpenGL renderer
+1
View File
@@ -354,6 +354,7 @@ struct mjvScene_ { // abstract scene passed to OpenGL renderer
// framing
int framewidth; // frame pixel width; 0: disable framing
float framergb[3]; // frame color
int status; // status; 0: ok, 1: geoms exhausted
};
typedef struct mjvScene_ mjvScene;
+5
View File
@@ -7139,6 +7139,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
),
doc='frame color',
),
StructFieldDecl(
name='status',
type=ValueType(name='int'),
doc='status; 0: ok, 1: geoms exhausted',
),
),
)),
('mjvFigure',
+1
View File
@@ -1196,6 +1196,7 @@ This is useful for example when the MJB is not available as a file on disk.)"));
X(scale);
X(stereo);
X(framewidth);
X(status);
#undef X
#define X(var) DefinePyArray(mjvScene, #var, &MjvSceneWrapper::var)
+58 -53
View File
@@ -73,9 +73,9 @@ static void makeLabel(const mjModel* m, mjtObj type, int id, char* label) {
// returns 1 if there are no more geoms available in the scene, 0 otherwise
static inline int geomsExhausted(mjData* d, mjvScene* scn) {
static inline int geomsExhausted(mjvScene* scn) {
if ( scn->ngeom>=scn->maxgeom ) {
mj_warning(d, mjWARN_VGEOMFULL, scn->maxgeom);
scn->status = 1;
return 1;
}
return 0;
@@ -203,7 +203,7 @@ static void addContactGeom(const mjModel* m, mjData* d, const mjtByte* flags,
// contact point
if (flags[mjVIS_CONTACTPOINT]) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -288,7 +288,7 @@ static void addContactGeom(const mjModel* m, mjData* d, const mjtByte* flags,
// draw the three axes (separate geoms)
for (int j=0; j < 3; j++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -369,7 +369,7 @@ static void addContactGeom(const mjModel* m, mjData* d, const mjtByte* flags,
}
// one-directional arrow for friction and world, symmetric otherwise
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -759,7 +759,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
(category & catmask)) {
for (int i=0; i < m->nflex; i++) {
if (vopt->flexgroup[mjMAX(0, mjMIN(mjNGROUP-1, m->flex_group[i]))]) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -808,7 +808,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
if (vopt->flags[mjVIS_SKIN] && (category & catmask)) {
for (int i=0; i < m->nskin; i++) {
if (vopt->skingroup[mjMAX(0, mjMIN(mjNGROUP-1, m->skin_group[i]))]) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -890,7 +890,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
rgba = m->vis.rgba.bvactive;
}
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -925,7 +925,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
rgba = m->vis.rgba.bvactive;
}
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -958,7 +958,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
for (int k=0; k < 2; k++) {
if (scn->ngeom >= scn->maxgeom) break;
if (i == 0) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -967,7 +967,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
releaseGeom(&thisgeom, scn);
}
if (j == 0) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -976,7 +976,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
releaseGeom(&thisgeom, scn);
}
if (k == 0) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1033,7 +1033,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
mju_mulMatVec3(pos, xmat, center);
mju_addTo3(pos, xpos);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1057,7 +1057,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
for (int b = 0; b < m->mesh_octnum[meshid]; b++) {
int i = b + m->mesh_octadr[meshid];
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1118,7 +1118,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
float* mesh_vert = m->mesh_vert + 3*m->mesh_vertadr[mesh_id];
int* face = m->mesh_face + 3*m->mesh_faceadr[mesh_id];
for (int i=0; i < m->mesh_facenum[mesh_id]; i++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
} else {
// triangle in global frame
@@ -1169,7 +1169,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
for (int i=1; i < m->nbody; i++) {
// skip if mass too small or if this body is static and static bodies are masked
if (m->body_mass[i] > mjMINVAL && (bodycategory(m, i) & catmask)) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1228,7 +1228,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
int i = pert->select;
if ((pert->active | pert->active2) & mjPERT_TRANSLATE) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1253,7 +1253,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
releaseGeom(&thisgeom, scn);
// add small sphere at end-effector
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1269,7 +1269,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
}
if ((pert->active | pert->active2) & mjPERT_ROTATE) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1327,7 +1327,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// draw the three axes (separate geoms)
for (int j=0; j < 3; j++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1366,7 +1366,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
mju_mulMatVec3(selpos, d->xmat+9*pert->select, pert->localpos);
mju_addTo3(selpos, d->xpos+3*pert->select);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1396,7 +1396,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
if (bodycategory(m, i) & ~catmask) {
continue;
}
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1425,7 +1425,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
sz[1] = m->vis.scale.jointlength * scl;
sz[0] = m->vis.scale.jointwidth * scl;
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1568,7 +1568,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
if (m->actuator_trntype[i] == mjTRN_JOINT ||
m->actuator_trntype[i] == mjTRN_JOINTINPARENT ||
m->actuator_trntype[i] == mjTRN_SITE) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1631,7 +1631,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// add inflated geom if it is a regular primitive
if (geomtype != mjGEOM_PLANE && geomtype != mjGEOM_HFIELD &&
geomtype != mjGEOM_MESH && geomtype != mjGEOM_SDF) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1658,7 +1658,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
else if (m->actuator_trntype[i] == mjTRN_TENDON && d->ten_wrapnum[j]) {
for (int k=d->ten_wrapadr[j]; k < d->ten_wrapadr[j]+d->ten_wrapnum[j]-1; k++) {
if (d->wrap_obj[k] != -2 && d->wrap_obj[k+1] != -2) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1705,7 +1705,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
if (m->body_dofnum[weld_id]) {
int islandid = d->dof_island[m->body_dofadr[weld_id]];
if (islandid > -1) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1743,7 +1743,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
int geomgroup = mjMAX(0, mjMIN(mjNGROUP-1, m->geom_group[i]));
if (vopt->geomgroup[geomgroup]) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1869,7 +1869,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
sz[0] = m->vis.scale.framewidth * scl;
sz[1] = m->vis.scale.framelength * scl;
for (int j=0; j < 3; j++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1911,7 +1911,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// show if group enabled
if (vopt->sitegroup[mjMAX(0, mjMIN(mjNGROUP-1, m->site_group[i]))]) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -1952,7 +1952,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
sz[0] = m->vis.scale.framewidth * scl;
sz[1] = m->vis.scale.framelength * scl;
for (int j=0; j < 3; j++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2041,21 +2041,21 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// triangulation and wireframe of the frustum
for (int e=0; e < 4; e++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
thisgeom = acquireGeom(scn, i, category, objtype);
makeTriangle(thisgeom, vnear[e], vfar[e], vnear[(e+1)%4], rgba);
releaseGeom(&thisgeom, scn);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
thisgeom = acquireGeom(scn, i, category, objtype);
makeTriangle(thisgeom, vfar[e], vfar[(e+1)%4], vnear[(e+1)%4], rgba);
releaseGeom(&thisgeom, scn);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2063,7 +2063,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
mjv_connector(thisgeom, mjGEOM_LINE, 3, vnear[e], vnear[(e+1)%4]);
f2f(thisgeom->rgba, rgba, 4);
releaseGeom(&thisgeom, scn);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2071,7 +2071,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
mjv_connector(thisgeom, mjGEOM_LINE, 3, vfar[e], vfar[(e+1)%4]);
f2f(thisgeom->rgba, rgba, 4);
releaseGeom(&thisgeom, scn);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2082,7 +2082,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
}
}
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2104,7 +2104,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
releaseGeom(&thisgeom, scn);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2140,7 +2140,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
sz[0] = m->vis.scale.framewidth * scl;
sz[1] = m->vis.scale.framelength * scl;
for (int j=0; j < 3; j++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2182,7 +2182,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// make light position: offset backward, to avoid casting shadow
mju_addScl3(vec, d->light_xpos+3*i, d->light_xdir+3*i, -scl * m->vis.scale.light -0.0001);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2215,7 +2215,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
sz[0] = m->vis.scale.framewidth * scl;
sz[1] = m->vis.scale.framelength * scl;
for (int j=0; j < 3; j++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2290,7 +2290,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
if (!draw_catenary) {
for (int j=d->ten_wrapadr[i]; j < d->ten_wrapadr[i]+d->ten_wrapnum[i]-1; j++) {
if (d->wrap_obj[j] != -2 && d->wrap_obj[j+1] != -2) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2378,7 +2378,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// draw npoints-1 segments
for (int j=0; j < npoints-1; j++) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2434,7 +2434,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
mju_addTo3(end, d->site_xpos+3*k);
// render slider
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2448,7 +2448,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
releaseGeom(&thisgeom, scn);
// render crank
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2471,7 +2471,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
if (vopt->flags[mjVIS_COM] && (category & catmask)) {
for (int i=1; i < m->nbody; i++) {
if (m->body_rootid[i] == i) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2500,7 +2500,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
cur = d->xipos+3*i;
if (m->body_jntnum[i]) {
for (int j=m->body_jntadr[i]+m->body_jntnum[i]-1; j >= m->body_jntadr[i]; j--) {
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2517,7 +2517,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
}
// connect first joint (or com) to parent com
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2545,7 +2545,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
}
// make ray
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2567,7 +2567,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
}
// make ray
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2593,7 +2593,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// map force to spatial vector in world frame
mju_scl3(vec, xfrc, m->vis.map.force/m->stat.meanmass);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2637,7 +2637,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
// construct geom
sz[0] = scl * m->vis.scale.constraint;
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -2648,7 +2648,7 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
}
releaseGeom(&thisgeom, scn);
if (geomsExhausted(d, scn)) {
if (geomsExhausted(scn)) {
return;
}
@@ -3282,6 +3282,7 @@ void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn) {
// clear geoms
scn->ngeom = 0;
scn->status = 0;
// trigger plugin visualization hooks
if (m->nplugin) {
@@ -3318,6 +3319,10 @@ void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
if (opt->flags[mjVIS_SKIN]) {
mjv_updateActiveSkin(m, d, scn, opt);
}
if (scn->status) {
mj_warning(d, mjWARN_VGEOMFULL, scn->maxgeom);
}
}
+2
View File
@@ -67,6 +67,7 @@ TEST_F(MjvSceneTest, UpdateScene) {
}
mjv_updateScene(model, data, &opt_, &pert_, &cam_, mjCAT_ALL, &scn_);
EXPECT_EQ(scn_.status, 0);
EXPECT_GT(scn_.ngeom, 0);
EXPECT_GT(scn_.nlight, 0);
if (model->nskin) EXPECT_GT(scn_.nskin, 0);
@@ -98,6 +99,7 @@ TEST_F(MjvSceneTest, UpdateSceneGeomsExhausted) {
// clear handlers to avoid test failure; we are explicitly expecting a warning
mju_clearHandlers();
mjv_updateScene(model, data, &opt_, &pert_, &cam_, mjCAT_ALL, &scn_);
EXPECT_EQ(scn_.status, 1);
EXPECT_EQ(scn_.ngeom, maxgeoms);
EXPECT_EQ(data->warning[mjWARN_VGEOMFULL].number, 1);
+1
View File
@@ -6286,6 +6286,7 @@ public unsafe struct mjvScene_ {
public fixed byte flags[10];
public int framewidth;
public fixed float framergb[3];
public int status;
}
[StructLayout(LayoutKind.Sequential)]