2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
10 **************************************************************************/
12 #include <cstdio> // FILE
13 #include <cstring> // strncmp
30 MOOF_REGISTER_RESOURCE(image
, png
, textures
);
32 //static int power_of_two(int input)
36 //while (value < input)
43 unsigned image::global_object_
= 0;
46 image::image(const std::string
& path
) :
49 min_filter_(GL_NEAREST
),
50 mag_filter_(GL_NEAREST
),
56 FILE* fp
= fopen(path
.c_str(), "rb");
57 if (!fp
) throw std::runtime_error("image not found at " + path
);
59 png_byte signature
[8];
62 png_infop pngInfo
= 0;
63 png_infop pngInfoEnd
= 0;
64 png_structp pngObj
= 0;
74 bytesRead
= fread(signature
, 1, sizeof(signature
), fp
);
75 if (bytesRead
< sizeof(signature
) ||
76 png_sig_cmp(signature
, 0, sizeof(signature
)) != 0) goto cleanup
;
78 pngObj
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, 0, 0, 0);
79 if (!pngObj
) goto cleanup
;
81 pngInfo
= png_create_info_struct(pngObj
);
82 if (!pngInfo
) goto cleanup
;
84 pngInfoEnd
= png_create_info_struct(pngObj
);
85 if (!pngInfoEnd
) goto cleanup
;
87 if (setjmp(png_jmpbuf(pngObj
))) goto cleanup
;
89 png_init_io(pngObj
, fp
);
90 png_set_sig_bytes(pngObj
, sizeof(signature
));
91 png_read_info(pngObj
, pngInfo
);
93 bpp
= png_get_bit_depth(pngObj
, pngInfo
);
94 colors
= png_get_color_type(pngObj
, pngInfo
);
97 case PNG_COLOR_TYPE_PALETTE
:
98 png_set_palette_to_rgb(pngObj
);
101 case PNG_COLOR_TYPE_GRAY
:
102 if (bpp
< 8) png_set_expand(pngObj
);
105 case PNG_COLOR_TYPE_GRAY_ALPHA
:
106 png_set_gray_to_rgb(pngObj
);
110 if (bpp
== 16) png_set_strip_16(pngObj
);
112 png_read_update_info(pngObj
, pngInfo
);
114 bpp
= png_get_bit_depth(pngObj
, pngInfo
);
115 channels_
= png_get_channels(pngObj
, pngInfo
);
116 depth_
= bpp
* channels_
;
119 png_get_text(pngObj
, pngInfo
, &texts
, &nutext_s
);
120 for (int i
= 0; i
< nutext_s
; ++i
)
122 if (strncmp(texts
[i
].key
, "TextureInfo", 11) == 0)
124 set_texture_info(texts
[i
].text
);
129 width_
= png_get_image_width(pngObj
, pngInfo
);
130 height_
= png_get_image_height(pngObj
, pngInfo
);
132 pitch_
= png_get_rowbytes(pngObj
, pngInfo
);
133 pixels_
= new char[width_
* pitch_
];
135 rows
= new png_bytep
[height_
];
136 for (int i
= 0; i
< height_
; ++i
)
138 rows
[height_
-1-i
] = (png_bytep
)(pixels_
+ i
* channels_
* width_
);
141 png_read_image(pngObj
, rows
);
142 png_read_end(pngObj
, 0);
147 png_destroy_read_struct(pngObj
? &pngObj
: 0,
148 pngInfo
? &pngInfo
: 0,
149 pngInfoEnd
? &pngInfoEnd
: 0);
160 void image::set_as_icon() const
164 SDL_Surface
* context
= SDL_CreateRGBSurfaceFrom
171 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
184 SDL_WM_SetIcon(context
, 0);
186 SDL_FreeSurface(context
);
190 bool image::tile_coordinates(int index
, scalar coords
[8]) const
192 // make sure the index represents a real tile
193 if (index
< 0 && index
>= tile_width_
* tile_height_
) return false;
195 scalar w
= 1.0 / scalar(tile_width_
);
196 scalar h
= 1.0 / scalar(tile_height_
);
198 coords
[0] = scalar(index
% tile_width_
) * w
;
199 coords
[1] = (scalar(tile_height_
- 1) - scalar(index
/ tile_width_
)) * h
;
200 coords
[2] = coords
[0] + w
;
201 coords
[3] = coords
[1];
202 coords
[4] = coords
[2];
203 coords
[5] = coords
[1] + h
;
204 coords
[6] = coords
[0];
205 coords
[7] = coords
[5];
211 void image::bind() const
213 ASSERT(video::current() && "should have a video context set");
219 if (object_
!= global_object_
)
221 glBindTexture(GL_TEXTURE_2D
, (GLuint
)object_
);
222 global_object_
= object_
;
226 void image::reset_binding()
228 ASSERT(video::current() && "should have a video context set");
230 glBindTexture(GL_TEXTURE_2D
, 0);
236 * Upload the image to GL so that it will be accessible by a much more
237 * manageable handle and hopefully reside in video memory.
239 void image::upload_to_gl() const
247 glGenTextures(1, (GLuint
*)&object_
);
248 glBindTexture(GL_TEXTURE_2D
, (GLuint
)object_
);
251 if (channels_
== 3) mode
= GL_RGB
;
271 // we want to know when the GL context is recreated
272 //dispatcher& dispatcher = dispatcher::global();
273 //new_context_ = dispatcher.add_target("video.newcontext",
274 //boost::bind(&image::context_recreated, this));
275 // FIXME this has const issues
278 void image::unload_from_gl() const
282 if (object_
== global_object_
)
287 glDeleteTextures(1, (GLuint
*)&object_
);
292 void image::context_recreated()
294 object_
= global_object_
= 0;
299 * Sets some texture properties such as the filters and external
300 * coordinate behavior.
302 void image::set_properties() const
304 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, min_filter_
);
305 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, mag_filter_
);
306 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, wrap_s_
);
307 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, wrap_t_
);
311 void image::set_texture_info(const std::string
& info
)
316 script::slot g
= script
.globals();
317 g
.set_field("CLAMP", GL_CLAMP
);
318 g
.set_field("REPEAT", GL_REPEAT
);
319 g
.set_field("LINEAR", GL_LINEAR
);
320 g
.set_field("NEAREST", GL_NEAREST
);
321 g
.set_field("LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR
);
322 g
.set_field("LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST
);
323 g
.set_field("NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR
);
324 g
.set_field("NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST
);
326 if (script
.do_string(info
) != script::success
)
334 log_info("loading texture information...");
336 script::slot globals
= script
.globals();
337 globals
.get(tile_width_
, "tiles_s");
338 globals
.get(tile_height_
, "tiles_t");
339 globals
.get(min_filter_
, "min_filter");
340 globals
.get(mag_filter_
, "mag_filter");
341 globals
.get(wrap_s_
, "wrap_s");
342 globals
.get(wrap_t_
, "wrap_t");