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
|
mjfReadResource read; // reading callback
|
||||||
mjfCloseResource close; // closing callback
|
mjfCloseResource close; // closing callback
|
||||||
mjfGetResourceDir getdir; // get directory callback (optional)
|
mjfGetResourceDir getdir; // get directory callback (optional)
|
||||||
|
mjfResourceModified modified; // resource modified callback (optional)
|
||||||
void* data; // opaque data pointer (resource invariant)
|
void* data; // opaque data pointer (resource invariant)
|
||||||
};
|
};
|
||||||
typedef struct mjpResourceProvider mjpResourceProvider;
|
typedef struct mjpResourceProvider mjpResourceProvider;
|
||||||
|
|||||||
@@ -330,8 +330,9 @@ Resource prefix
|
|||||||
|
|
||||||
Callbacks
|
Callbacks
|
||||||
There are three callbacks that a resource provider is required to implement: :ref:`open<mjfOpenResource>`,
|
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>`
|
:ref:`read<mjfReadResource>`, and :ref:`close<mjfCloseResource>`. The other two callback
|
||||||
is optional. More details on these callbacks are given below.
|
:ref:`getdir<mjfGetResourceDir>` and :ref:`modified<mjfModifiedResource>` are optional. More details on these callbacks
|
||||||
|
are given below.
|
||||||
|
|
||||||
Data Pointer
|
Data Pointer
|
||||||
Lastly, there's an opaque data pointer for the provider to pass data into the callbacks. This data pointer is constant
|
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
|
- :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
|
resource name. For example, the resource name ``http://www.example.com/myasset.obj`` would have
|
||||||
``http://www.example.com/`` as its directory.
|
``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:
|
.. _exProviderUsage:
|
||||||
|
|
||||||
@@ -421,6 +424,6 @@ Now we can write assets as strings in our MJCF files:
|
|||||||
|
|
||||||
<asset>
|
<asset>
|
||||||
<texture name="grid" file="grid.png" type="2d"/>
|
<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>
|
</asset>
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ typedef void (*mjfCloseResource)(mjResource* resource);
|
|||||||
// sets dir to directory string with ndir being size of directory string
|
// sets dir to directory string with ndir being size of directory string
|
||||||
typedef void (*mjfGetResourceDir)(mjResource* resource, const char** dir, int* ndir);
|
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 describing a single resource provider
|
||||||
struct mjpResourceProvider {
|
struct mjpResourceProvider {
|
||||||
const char* prefix; // prefix for match against a resource name
|
const char* prefix; // prefix for match against a resource name
|
||||||
@@ -50,6 +55,7 @@ struct mjpResourceProvider {
|
|||||||
mjfReadResource read; // reading callback
|
mjfReadResource read; // reading callback
|
||||||
mjfCloseResource close; // closing callback
|
mjfCloseResource close; // closing callback
|
||||||
mjfGetResourceDir getdir; // get directory callback (optional)
|
mjfGetResourceDir getdir; // get directory callback (optional)
|
||||||
|
mjfResourceModified modified; // resource modified callback (optional)
|
||||||
void* data; // opaque data pointer (resource invariant)
|
void* data; // opaque data pointer (resource invariant)
|
||||||
};
|
};
|
||||||
typedef struct mjpResourceProvider mjpResourceProvider;
|
typedef struct mjpResourceProvider mjpResourceProvider;
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ bool ResourceProvidersAreIdentical(const mjpResourceProvider* p1, const mjpResou
|
|||||||
p1->read == p2->read &&
|
p1->read == p2->read &&
|
||||||
p1->close == p2->close &&
|
p1->close == p2->close &&
|
||||||
p1->getdir == p2->getdir &&
|
p1->getdir == p2->getdir &&
|
||||||
|
p1->modified == p2->modified &&
|
||||||
p1->data == p2->data);
|
p1->data == p2->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,17 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.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 <mujoco/mjplugin.h>
|
||||||
#include "engine/engine_plugin.h"
|
#include "engine/engine_plugin.h"
|
||||||
@@ -28,6 +39,7 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t* buffer; // raw bytes from file
|
uint8_t* buffer; // raw bytes from file
|
||||||
size_t nbuffer; // size of buffer in bytes
|
size_t nbuffer; // size of buffer in bytes
|
||||||
|
time_t mtime; // last modified time
|
||||||
} file_buffer;
|
} file_buffer;
|
||||||
|
|
||||||
// open the given resource; if the name doesn't have a prefix matching with a
|
// 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);
|
mju_closeResource(resource);
|
||||||
return NULL;
|
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;
|
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
|
// get the length of the dirname portion of a given path
|
||||||
int mju_dirnamelen(const char* path) {
|
int mju_dirnamelen(const char* path) {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ mjResource* mju_openVfsResource(const char* name, const mjVFS* vfs) {
|
|||||||
.read = &vfs_read_callback,
|
.read = &vfs_read_callback,
|
||||||
.close = &vfs_close_callback,
|
.close = &vfs_close_callback,
|
||||||
.getdir = &vfs_getdir_callback,
|
.getdir = &vfs_getdir_callback,
|
||||||
|
.modified = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// create resource
|
// create resource
|
||||||
|
|||||||
Reference in New Issue
Block a user