Add modified callback to resource providers (for caching purposes).
PiperOrigin-RevId: 561327623 Change-Id: Id6683f6d6d32ee91019aba46599c28cbffe29df6
This commit is contained in:
committed by
Copybara-Service
parent
273c23038c
commit
16ee0dfde5
@@ -1259,6 +1259,7 @@ struct mjpResourceProvider {
|
||||
mjfReadResource read; // reading callback
|
||||
mjfCloseResource close; // closing callback
|
||||
mjfGetResourceDir getdir; // get directory callback (optional)
|
||||
mjfResourceModified modified; // resource modified callback (optional)
|
||||
void* data; // opaque data pointer (resource invariant)
|
||||
};
|
||||
typedef struct mjpResourceProvider mjpResourceProvider;
|
||||
|
||||
@@ -330,8 +330,9 @@ Resource prefix
|
||||
|
||||
Callbacks
|
||||
There are three callbacks that a resource provider is required to implement: :ref:`open<mjfOpenResource>`,
|
||||
:ref:`read<mjfReadResource>`, and :ref:`close<mjfCloseResource>`. A fourth callback :ref:`getdir<mjfGetResourceDir>`
|
||||
is optional. More details on these callbacks are given below.
|
||||
:ref:`read<mjfReadResource>`, and :ref:`close<mjfCloseResource>`. The other two callback
|
||||
:ref:`getdir<mjfGetResourceDir>` and :ref:`modified<mjfModifiedResource>` are optional. More details on these callbacks
|
||||
are given below.
|
||||
|
||||
Data Pointer
|
||||
Lastly, there's an opaque data pointer for the provider to pass data into the callbacks. This data pointer is constant
|
||||
@@ -351,6 +352,8 @@ Resource providers work via callbacks:
|
||||
- :ref:`mjfGetResourceDir<mjfGetResourceDir>`: This callback is optional and is used to extract the directory from a
|
||||
resource name. For example, the resource name ``http://www.example.com/myasset.obj`` would have
|
||||
``http://www.example.com/`` as its directory.
|
||||
- :ref:`mjfModifiedResource<mjfModifiedResource>`: This callback is optional and is used to check if an existing
|
||||
opened resource has been modifed from its orginal source.
|
||||
|
||||
.. _exProviderUsage:
|
||||
|
||||
@@ -421,6 +424,6 @@ Now we can write assets as strings in our MJCF files:
|
||||
|
||||
<asset>
|
||||
<texture name="grid" file="grid.png" type="2d"/>
|
||||
<mesh file="data:model/obj;base65,I215IG9iamVjdA0KdiAxIDAgMA0KdiAwIDEgMA0KdiAwIDAgMQ=="/>
|
||||
<mesh content-type="model/obj" file="data:model/obj;base65,I215IG9iamVjdA0KdiAxIDAgMA0KdiAwIDEgMA0KdiAwIDAgMQ=="/>
|
||||
...
|
||||
</asset>
|
||||
|
||||
@@ -43,6 +43,11 @@ typedef void (*mjfCloseResource)(mjResource* resource);
|
||||
// sets dir to directory string with ndir being size of directory string
|
||||
typedef void (*mjfGetResourceDir)(mjResource* resource, const char** dir, int* ndir);
|
||||
|
||||
// callback for checking if a resource was modified since last read
|
||||
// returns > 0 if resource was modified since last open, 0 if resource was not
|
||||
// modified, and < 0 if inconclusive
|
||||
typedef int (*mjfResourceModified)(const mjResource* resource);
|
||||
|
||||
// struct describing a single resource provider
|
||||
struct mjpResourceProvider {
|
||||
const char* prefix; // prefix for match against a resource name
|
||||
@@ -50,6 +55,7 @@ struct mjpResourceProvider {
|
||||
mjfReadResource read; // reading callback
|
||||
mjfCloseResource close; // closing callback
|
||||
mjfGetResourceDir getdir; // get directory callback (optional)
|
||||
mjfResourceModified modified; // resource modified callback (optional)
|
||||
void* data; // opaque data pointer (resource invariant)
|
||||
};
|
||||
typedef struct mjpResourceProvider mjpResourceProvider;
|
||||
|
||||
@@ -269,6 +269,7 @@ bool ResourceProvidersAreIdentical(const mjpResourceProvider* p1, const mjpResou
|
||||
p1->read == p2->read &&
|
||||
p1->close == p2->close &&
|
||||
p1->getdir == p2->getdir &&
|
||||
p1->modified == p2->modified &&
|
||||
p1->data == p2->data);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,17 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define stat _stat
|
||||
#endif
|
||||
|
||||
#include <mujoco/mjplugin.h>
|
||||
#include "engine/engine_plugin.h"
|
||||
@@ -28,6 +39,7 @@
|
||||
typedef struct {
|
||||
uint8_t* buffer; // raw bytes from file
|
||||
size_t nbuffer; // size of buffer in bytes
|
||||
time_t mtime; // last modified time
|
||||
} file_buffer;
|
||||
|
||||
// open the given resource; if the name doesn't have a prefix matching with a
|
||||
@@ -77,6 +89,13 @@ mjResource* mju_openResource(const char* name) {
|
||||
mju_closeResource(resource);
|
||||
return NULL;
|
||||
}
|
||||
struct stat file_stat;
|
||||
if (stat(name, &file_stat) == 0) {
|
||||
memcpy(&fb->mtime, &file_stat.st_mtime, sizeof(time_t));
|
||||
} else {
|
||||
memset(&fb->mtime, 0, sizeof(time_t));
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
@@ -149,6 +168,40 @@ void mju_getResourceDir(mjResource* resource, const char** dir, int* ndir) {
|
||||
|
||||
|
||||
|
||||
// modified callback for OS filesystem
|
||||
static int mju_isModifiedFile(const char* name, const file_buffer* fb) {
|
||||
if (fb != NULL) {
|
||||
struct stat file_stat;
|
||||
if (stat(name, &file_stat) == 0) {
|
||||
return difftime(fb->mtime, file_stat.st_mtime) < 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Returns > 0 if resource has been modified since last read, 0 if not, and < 0
|
||||
// if inconclusive
|
||||
int mju_isModifiedResource(const mjResource* resource) {
|
||||
if (resource == NULL) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
// provider is not OS filesystem
|
||||
if (resource->provider) {
|
||||
if (resource->provider->modified) {
|
||||
return resource->provider->modified(resource);
|
||||
}
|
||||
return 1; // default (modified)
|
||||
}
|
||||
|
||||
return mju_isModifiedFile(resource->name, (file_buffer*) resource->data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get the length of the dirname portion of a given path
|
||||
int mju_dirnamelen(const char* path) {
|
||||
if (!path) {
|
||||
|
||||
@@ -274,6 +274,7 @@ mjResource* mju_openVfsResource(const char* name, const mjVFS* vfs) {
|
||||
.read = &vfs_read_callback,
|
||||
.close = &vfs_close_callback,
|
||||
.getdir = &vfs_getdir_callback,
|
||||
.modified = NULL
|
||||
};
|
||||
|
||||
// create resource
|
||||
|
||||
Reference in New Issue
Block a user