gKit2 light
material_data.cpp
Go to the documentation of this file.
1 
3 #include <cstdio>
4 #include <algorithm>
5 
6 #include "image_io.h"
7 #include "texture.h"
8 #include "material_data.h"
9 #include "mesh_data.h"
10 
11 
13 {
14  ImageData diffuse_image;
15  bool use_diffuse= false;
16 
17  ImageData ns_image;
18  bool use_ns= false;
19 };
20 
21 static
22 int miplevel_size( const ImageData& image, const int lod )
23 {
24  int w= std::max(1, image.width / (1<<lod));
25  int h= std::max(1, image.height / (1<<lod));
26  return image.channels * image.size * w * h;
27 }
28 
29 static inline
30 int offset( const int width, const int stride, const int x, const int y, const int c )
31 {
32  return (y * width + x) * stride + c;
33 }
34 
35 static
36 ImageData mipmap_resize( const ImageData& image, const int lod )
37 {
38  assert(image.size == 1);
39 
40  ImageData level= ImageData(image.width, image.height, image.channels, image.size);
41  level.pixels= image.pixels;
42 
43  int w= level.width;
44  int h= level.height;
45  int stride= level.channels * level.size;
46  int row_stride= image.width; // "preserve" les images de largeur impaire...
47  for(int l= 0; l < lod; l++)
48  {
49  w= std::max(1, w / 2);
50  h= std::max(1, h / 2);
51 
52  for(int y= 0; y < h; y++)
53  for(int x= 0; x < w; x++)
54  for(int i= 0; i < image.channels; i++)
55  {
56  int m= 0;
57  m= m + level.pixels[offset(row_stride, stride, 2*x, 2*y, i)];
58  m= m + level.pixels[offset(row_stride, stride, 2*x +1, 2*y, i)];
59  m= m + level.pixels[offset(row_stride, stride, 2*x, 2*y +1, i)];
60  m= m + level.pixels[offset(row_stride, stride, 2*x +1, 2*y +1, i)];
61 
62  level.pixels[offset(w, stride, x, y, i)]= m / 4;
63  }
64 
65  row_stride= w;
66  }
67 
68  //~ printf(" resize %d : %dx%d, %dx%d\n", lod, image.width, image.height, w, h);
69 
70  level.width= w;
71  level.height= h;
72  return level;
73 }
74 
75 static
76 Color average_color( const ImageData& image )
77 {
78  assert(image.size == 1);
79 
80  float color[4]= {0, 0, 0, 0};
81 
82  int stride= image.channels * image.size;
83  for(int y= 0; y < image.height; y++)
84  for(int x= 0; x < image.width; x++)
85  for(int i= 0; i < image.channels; i++)
86  color[i]= color[i] + (float) image.pixels[offset(image.width, stride, x, y, i)] / 255.f;
87 
88  return Color(color[0], color[1], color[2], color[3]) / (image.width * image.height);
89 }
90 
91 
92 int read_textures( std::vector<MaterialData>& materials, const size_t max_size )
93 {
94  std::vector<TextureData> textures;
95 
96  // evalue la taille totale occuppee par toutes les images / textures
97  size_t total_size= 0;
98  for(int i= 0; i < (int) materials.size(); i++)
99  {
100  const MaterialData &material= materials[i];
101  TextureData data;
102 
103  if(!material.diffuse_filename.empty())
104  {
105  data.use_diffuse= true;
106  data.diffuse_image= read_image_data(material.diffuse_filename.c_str());
107  total_size= total_size + data.diffuse_image.width * data.diffuse_image.height * data.diffuse_image.channels * data.diffuse_image.size;
108  }
109  if(!material.ns_filename.empty())
110  {
111  data.use_ns= true;
112  data.ns_image= read_image_data(material.ns_filename.c_str());
113  total_size= total_size + data.ns_image.width * data.ns_image.height * data.ns_image.channels * data.ns_image.size;
114  }
115 
116  if(total_size > max_size)
117  {
118  // ne stocke plus les images apres avoir depasse la limite de taille
119  std::vector<unsigned char>().swap(data.diffuse_image.pixels);
120  std::vector<unsigned char>().swap(data.ns_image.pixels);
121  }
122 
123  textures.emplace_back(data);
124  }
125 
126  printf("using %dMB / %dMB\n", int(total_size / 1024 / 1024), int(max_size / 1024 / 1024));
127 
128  // reduit les dimensions des images / textures jusqu'a respecter la limite de taille
129  int lod= 0;
130  for(; total_size > max_size ; lod++)
131  {
132  total_size= 0;
133  for(int i= 0; i < (int) textures.size(); i++)
134  {
135  if(textures[i].use_diffuse)
136  total_size= total_size + miplevel_size(textures[i].diffuse_image, lod);
137  if(textures[i].use_ns)
138  total_size= total_size + miplevel_size(textures[i].ns_image, lod);
139  }
140  }
141 
142  printf(" lod %d, %dMB\n", lod, int(total_size / 1024 / 1024));
143 
144  // charge une texture par defaut, en cas d'erreur de chargement
145  GLuint default_texture= read_texture(0, "data/grid.png");
146 
147  printf("resizing textures...\n");
148  // construit les textures a la bonne resolution
149  for(int i= 0; i < (int) textures.size(); i++)
150  {
151  TextureData& data= textures[i];
152  MaterialData& material= materials[i];
153 
154  if(data.use_diffuse && data.diffuse_image.width > 0)
155  {
156  if(data.diffuse_image.pixels.empty())
157  {
158  // recharge l'image, si necessaire
159  data.diffuse_image= read_image_data(material.diffuse_filename.c_str());
160  assert(data.diffuse_image.width > 0);
161  }
162 
163  ImageData level= mipmap_resize(data.diffuse_image, lod);
164  material.diffuse_texture= make_texture(0, level);
165 
166  material.diffuse_texture_color= average_color(level);
167  }
168  else
169  material.diffuse_texture= default_texture;
170 
171  if(data.use_ns && data.ns_image.width > 0)
172  {
173  if(data.ns_image.pixels.empty())
174  {
175  // recharge l'image, si necessaire
176  data.ns_image= read_image_data(material.ns_filename.c_str());
177  assert(data.ns_image.width > 0);
178  }
179 
180  ImageData level= mipmap_resize(data.ns_image, lod);
181  material.ns_texture= make_texture(0, level);
182  }
183  else
184  material.ns_texture= default_texture;
185 
186  // nettoyage, les images ne sont plus necessaires
187  std::vector<unsigned char>().swap(data.diffuse_image.pixels);
188  std::vector<unsigned char>().swap(data.ns_image.pixels);
189  }
190 
191  return total_size;
192 }
193 
194 void release_textures( std::vector<MaterialData>& materials )
195 {
196  for(int i= 0; i < (int) materials.size(); i++)
197  {
198  const MaterialData& material= materials[i];
199 
200  if(material.diffuse_texture > 0)
201  glDeleteTextures(1, &material.diffuse_texture);
202  if(material.ns_texture > 0)
203  glDeleteTextures(1, &material.ns_texture);
204  }
205 }
206 
void printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
Definition: text.cpp:140
ImageData read_image_data(const char *filename)
charge les donnees d'un fichier png. renvoie une image initialisee par defaut en cas d'echec.
Definition: image_io.cpp:216
Point max(const Point &a, const Point &b)
renvoie la plus grande composante de chaque point. x, y, z= max(a.x, b.x), max(a.y,...
Definition: vec.cpp:35
GLuint make_texture(const int unit, const int width, const int height, const GLenum texel_type, const GLenum data_format, const GLenum data_type)
creation de textures filtrables / mipmaps
Definition: texture.cpp:25
GLuint read_texture(const int unit, const char *filename, const GLenum texel_type)
Definition: texture.cpp:154
void release_textures(std::vector< MaterialData > &materials)
detruit les textures.
int read_textures(std::vector< MaterialData > &materials, const size_t max_size)
charge les textures associees a un ensemble de matieres, sans depasser une limite de taille,...
charge les textures utiilisees par un ensemble de matieres.
representation des donnees d'un fichier wavefront .obj
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:14
stockage temporaire des donnees d'une image.
Definition: image_io.h:38
representation d'une matiere texturee.
Definition: mesh_data.h:16
GLuint diffuse_texture
texture diffuse
Definition: mesh_data.h:21
std::string diffuse_filename
nom de la texture diffuse
Definition: mesh_data.h:20
GLuint ns_texture
texture exposant
Definition: mesh_data.h:29
std::string ns_filename
nom de la texture exposant
Definition: mesh_data.h:28
Color diffuse_texture_color
couleur moyenne de la texture
Definition: mesh_data.h:18