20
20
#include < cstddef>
21
21
#include < cstdint>
22
22
#include < cstdio>
23
+ #include < cstdlib>
23
24
#include < cstring>
24
25
#include < deque>
25
26
#include < functional>
@@ -59,8 +60,9 @@ class PNGImage {
59
60
int Height () const { return height_; }
60
61
bool IsSRGB () const { return is_srgb_; }
61
62
62
- uint8_t operator [] (int i) const { return data_[i]; }
63
- std::vector<unsigned char >& MoveData () { return data_; }
63
+ std::byte operator [] (int i) const { return data_[i]; }
64
+
65
+ mjByteVec&& MoveData() && { return std::move (data_); }
64
66
65
67
private:
66
68
std::size_t Size () const {
@@ -71,7 +73,7 @@ class PNGImage {
71
73
int height_;
72
74
bool is_srgb_;
73
75
LodePNGColorType color_type_;
74
- std::vector< uint8_t > data_;
76
+ mjByteVec data_;
75
77
};
76
78
77
79
PNGImage PNGImage::Load (const mjCBase* obj, mjResource* resource,
@@ -113,7 +115,12 @@ PNGImage PNGImage::Load(const mjCBase* obj, mjResource* resource,
113
115
lodepng::State state;
114
116
state.info_raw .colortype = image.color_type_ ;
115
117
state.info_raw .bitdepth = 8 ;
116
- unsigned err = lodepng::decode (image.data_ , w, h, state, buffer, nbuffer);
118
+ unsigned char * data_ptr = nullptr ;
119
+ unsigned err = lodepng_decode (&data_ptr, &w, &h, &state, buffer, nbuffer);
120
+ struct free_delete {
121
+ void operator ()(unsigned char * ptr) const { std::free (ptr); }
122
+ };
123
+ std::unique_ptr<unsigned char , free_delete> data{data_ptr};
117
124
118
125
// check for errors
119
126
if (err) {
@@ -122,6 +129,13 @@ PNGImage PNGImage::Load(const mjCBase* obj, mjResource* resource,
122
129
throw mjCError (obj, " %s" , ss.str ().c_str ());
123
130
}
124
131
132
+ if (data) {
133
+ size_t buffersize = lodepng_get_raw_size (w, h, &state.info_raw );
134
+ image.data_ .insert (image.data_ .end (),
135
+ reinterpret_cast <std::byte*>(data.get ()),
136
+ reinterpret_cast <std::byte*>(&data.get ()[buffersize]));
137
+ }
138
+
125
139
image.width_ = w;
126
140
image.height_ = h;
127
141
image.is_srgb_ = (state.info_png .srgb_defined == 1 );
@@ -4890,7 +4904,7 @@ void mjCTexture::BuiltinCube(void) {
4890
4904
4891
4905
// load PNG file
4892
4906
void mjCTexture::LoadPNG (mjResource* resource,
4893
- std::vector<unsigned char >& image,
4907
+ std::vector<std::byte >& image,
4894
4908
unsigned int & w, unsigned int & h, bool & is_srgb) {
4895
4909
LodePNGColorType color_type;
4896
4910
if (nchannel == 4 ) {
@@ -4907,13 +4921,14 @@ void mjCTexture::LoadPNG(mjResource* resource,
4907
4921
w = png_image.Width ();
4908
4922
h = png_image.Height ();
4909
4923
is_srgb = png_image.IsSRGB ();
4910
- image = png_image.MoveData ();
4924
+
4925
+ // Move data into image.
4926
+ image = std::move (png_image).MoveData ();
4911
4927
}
4912
4928
4913
4929
// load KTX file
4914
- void mjCTexture::LoadKTX (mjResource* resource,
4915
- std::vector<unsigned char >& image, unsigned int & w,
4916
- unsigned int & h, bool & is_srgb) {
4930
+ void mjCTexture::LoadKTX (mjResource* resource, std::vector<std::byte>& image,
4931
+ unsigned int & w, unsigned int & h, bool & is_srgb) {
4917
4932
const void * buffer = 0 ;
4918
4933
int buffer_sz = mju_readResource (resource, &buffer);
4919
4934
@@ -4933,8 +4948,7 @@ void mjCTexture::LoadKTX(mjResource* resource,
4933
4948
}
4934
4949
4935
4950
// load custom file
4936
- void mjCTexture::LoadCustom (mjResource* resource,
4937
- std::vector<unsigned char >& image,
4951
+ void mjCTexture::LoadCustom (mjResource* resource, std::vector<std::byte>& image,
4938
4952
unsigned int & w, unsigned int & h, bool & is_srgb) {
4939
4953
const void * buffer = 0 ;
4940
4954
int buffer_sz = mju_readResource (resource, &buffer);
@@ -4972,11 +4986,44 @@ void mjCTexture::LoadCustom(mjResource* resource,
4972
4986
memcpy (image.data (), (void *)(pint+2 ), w*h*3 *sizeof (char ));
4973
4987
}
4974
4988
4989
+ void mjCTexture::FlipIfNeeded (std::vector<std::byte>& image, unsigned int w,
4990
+ unsigned int h) {
4991
+ // horizontal flip
4992
+ if (hflip) {
4993
+ for (int r = 0 ; r < h; r++) {
4994
+ for (int c = 0 ; c < w / 2 ; c++) {
4995
+ int c1 = w - 1 - c;
4996
+ auto val1 = nchannel * (r * w + c);
4997
+ auto val2 = nchannel * (r * w + c1);
4998
+ for (int ch = 0 ; ch < nchannel; ch++) {
4999
+ auto tmp = image[val1 + ch];
5000
+ image[val1 + ch] = image[val2 + ch];
5001
+ image[val2 + ch] = tmp;
5002
+ }
5003
+ }
5004
+ }
5005
+ }
4975
5006
5007
+ // vertical flip
5008
+ if (vflip) {
5009
+ for (int r = 0 ; r < h / 2 ; r++) {
5010
+ for (int c = 0 ; c < w; c++) {
5011
+ int r1 = h - 1 - r;
5012
+ auto val1 = nchannel * (r * w + c);
5013
+ auto val2 = nchannel * (r1 * w + c);
5014
+ for (int ch = 0 ; ch < nchannel; ch++) {
5015
+ auto tmp = image[val1 + ch];
5016
+ image[val1 + ch] = image[val2 + ch];
5017
+ image[val2 + ch] = tmp;
5018
+ }
5019
+ }
5020
+ }
5021
+ }
5022
+ }
4976
5023
4977
5024
// load from PNG or custom file, flip if specified
4978
5025
void mjCTexture::LoadFlip (std::string filename, const mjVFS* vfs,
4979
- std::vector<unsigned char >& image,
5026
+ std::vector<std::byte >& image,
4980
5027
unsigned int & w, unsigned int & h, bool & is_srgb) {
4981
5028
std::string asset_type = GetAssetContentType (filename, content_type_);
4982
5029
@@ -5008,93 +5055,25 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
5008
5055
throw err;
5009
5056
}
5010
5057
5011
- // horizontal flip
5012
- if (hflip) {
5013
- if (nchannel != 3 ) {
5014
- throw mjCError (
5015
- this , " currently only 3-channel textures support horizontal flip" );
5016
- }
5017
- for (int r=0 ; r < h; r++) {
5018
- for (int c=0 ; c < w/2 ; c++) {
5019
- int c1 = w-1 -c;
5020
- unsigned char tmp[3 ] = {
5021
- image[3 *(r*w+c)],
5022
- image[3 *(r*w+c)+1 ],
5023
- image[3 *(r*w+c)+2 ]
5024
- };
5025
-
5026
- image[3 *(r*w+c)] = image[3 *(r*w+c1)];
5027
- image[3 *(r*w+c)+1 ] = image[3 *(r*w+c1)+1 ];
5028
- image[3 *(r*w+c)+2 ] = image[3 *(r*w+c1)+2 ];
5029
-
5030
- image[3 *(r*w+c1)] = tmp[0 ];
5031
- image[3 *(r*w+c1)+1 ] = tmp[1 ];
5032
- image[3 *(r*w+c1)+2 ] = tmp[2 ];
5033
- }
5034
- }
5035
- }
5036
-
5037
- // vertical flip
5038
- if (vflip) {
5039
- if (nchannel != 3 ) {
5040
- throw mjCError (
5041
- this , " currently only 3-channel textures support vertical flip" );
5042
- }
5043
- for (int r=0 ; r < h/2 ; r++) {
5044
- for (int c=0 ; c < w; c++) {
5045
- int r1 = h-1 -r;
5046
- unsigned char tmp[3 ] = {
5047
- image[3 *(r*w+c)],
5048
- image[3 *(r*w+c)+1 ],
5049
- image[3 *(r*w+c)+2 ]
5050
- };
5051
-
5052
- image[3 *(r*w+c)] = image[3 *(r1*w+c)];
5053
- image[3 *(r*w+c)+1 ] = image[3 *(r1*w+c)+1 ];
5054
- image[3 *(r*w+c)+2 ] = image[3 *(r1*w+c)+2 ];
5055
-
5056
- image[3 *(r1*w+c)] = tmp[0 ];
5057
- image[3 *(r1*w+c)+1 ] = tmp[1 ];
5058
- image[3 *(r1*w+c)+2 ] = tmp[2 ];
5059
- }
5060
- }
5061
- }
5058
+ FlipIfNeeded (image, w, h);
5062
5059
}
5063
5060
5064
-
5065
-
5066
5061
// load 2D
5067
5062
void mjCTexture::Load2D (std::string filename, const mjVFS* vfs) {
5068
5063
// load PNG or custom
5069
5064
unsigned int w, h;
5070
5065
bool is_srgb;
5071
- std::vector< unsigned char > image;
5072
- LoadFlip (filename, vfs, image , w, h, is_srgb);
5066
+
5067
+ LoadFlip (filename, vfs, data_ , w, h, is_srgb);
5073
5068
5074
5069
// assign size
5075
5070
width = w;
5076
5071
height = h;
5077
5072
if (colorspace == mjCOLORSPACE_AUTO) {
5078
5073
colorspace = is_srgb ? mjCOLORSPACE_SRGB : mjCOLORSPACE_LINEAR;
5079
5074
}
5080
-
5081
- // allocate and copy data
5082
- std::int64_t size = static_cast <std::int64_t >(width)*height;
5083
- if (size >= std::numeric_limits<int >::max () / nchannel || size <= 0 ) {
5084
- throw mjCError (this , " Texture too large" );
5085
- }
5086
- try {
5087
- data_.assign (nchannel*size, std::byte (0 ));
5088
- } catch (const std::bad_alloc& e) {
5089
- throw mjCError (this , " Could not allocate memory for texture '%s' (id %d)" ,
5090
- (const char *)file_.c_str (), id);
5091
- }
5092
- memcpy (data_.data (), image.data (), nchannel*size);
5093
- image.clear ();
5094
5075
}
5095
5076
5096
-
5097
-
5098
5077
// load cube or skybox from single file (repeated or grid)
5099
5078
void mjCTexture::LoadCubeSingle (std::string filename, const mjVFS* vfs) {
5100
5079
// check gridsize
@@ -5105,7 +5084,7 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
5105
5084
// load PNG or custom
5106
5085
unsigned int w, h;
5107
5086
bool is_srgb;
5108
- std::vector<unsigned char > image;
5087
+ std::vector<std::byte > image;
5109
5088
LoadFlip (filename, vfs, image, w, h, is_srgb);
5110
5089
5111
5090
if (colorspace == mjCOLORSPACE_AUTO) {
@@ -5226,7 +5205,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
5226
5205
// load PNG or custom
5227
5206
unsigned int w, h;
5228
5207
bool is_srgb;
5229
- std::vector<unsigned char > image;
5208
+ std::vector<std::byte > image;
5230
5209
LoadFlip (filename.Str (), vfs, image, w, h, is_srgb);
5231
5210
5232
5211
// assume all faces have the same colorspace
@@ -5308,6 +5287,9 @@ void mjCTexture::Compile(const mjVFS* vfs) {
5308
5287
throw mjCError (this , " Texture buffer has incorrect size, given %d expected %d" , nullptr ,
5309
5288
data_.size (), nchannel * width * height);
5310
5289
}
5290
+
5291
+ // Flip if specified.
5292
+ FlipIfNeeded (data_, width, height);
5311
5293
return ;
5312
5294
}
5313
5295
0 commit comments