From 62f3ceaff75a6b08cb1aec9a465773bb81a2d79d Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Wed, 13 Jul 2011 00:39:05 -0600 Subject: [PATCH] compression functions; fixed texture seams --- data/textures/BigExplosion.png | Bin 4883 -> 4899 bytes data/textures/Bonuses.png | Bin 1652 -> 1668 bytes data/textures/Building.png | Bin 2520 -> 2536 bytes data/textures/Particles.png | Bin 1455 -> 1471 bytes data/textures/TowerBlock1.png | Bin 1376 -> 1392 bytes data/textures/Trees.png | Bin 1250 -> 1266 bytes src/moof/compression.cc | 111 ++++++++ src/moof/compression.hh | 26 ++ src/moof/debug.hh | 10 +- src/moof/image.cc | 347 +++++++++++++++++++---- src/moof/image.hh | 21 +- src/moof/mesh.cc | 489 ++++++++++++++++----------------- src/moof/mesh.hh | 6 +- src/moof/video.cc | 14 +- src/moof/video.hh | 14 +- 15 files changed, 696 insertions(+), 342 deletions(-) create mode 100644 src/moof/compression.cc create mode 100644 src/moof/compression.hh diff --git a/data/textures/BigExplosion.png b/data/textures/BigExplosion.png index 7681d1bfd4a21a003c1e199360c6719655e08f48..f02f001e016947ecae3baf5f4ae8ef598ba26ebc 100644 GIT binary patch delta 67 zcmbQNwpeX~p#Xb{r>`sfEk;omd4~6`d$�(_*ZfnByQGAL1YH>f-LIqu}i0=o#7NaPOxbcjhuoV;av>59q<~WGQhxo_4y12XQC^-8#`Ub$b R6E|zKwEej^YvZFytN_NL7Z?Bl delta 37 tcmZqS{lYWBaH5O)L_=Z5yoosu>^ch0K90Tt6Ax>%9CZ`?u<_F*RsieL4OsvH diff --git a/data/textures/Building.png b/data/textures/Building.png index 1965bd11551ff2103d8b46fb79a2e14c4c37ad61..50ad4c7060f05308438339b6eb4da841faeffb35 100644 GIT binary patch delta 67 zcmca1{6ctwp#Xb{r>`sfEk;om38CQHD9ed@T8woQa~#CuL;T}iUEE!D6r6n=eFI?J RiJP@q+Wy>|weit64gj<-7WDuC delta 37 tcmaDMd_#DG;Y1hpiH5?Ac@uLS*mV?~eH?uQCLY#iIqD|(VdJN7902(P4ix|Z diff --git a/data/textures/Particles.png b/data/textures/Particles.png index bcc011c449e1dc8d333d6f53a8918ef83e227c07..1d430ccb1b4437bda36119db34792bdada7ed3bb 100644 GIT binary patch delta 67 zcmZ3_y`Ou6p#Xb{r>`sfEk;omdCLtAru!!9X))GK%yAHp5Alz8b#ZsqQE>Kg^bLS< RCvMheY5Q|;*2YI?Spdc|7gPWM delta 37 tcmdnby`Fo5;Y1hpiH5?Ac@uLS*mV?~eH?uQCLY#iIqD|(VdJN>ECA~D4Tb;! diff --git a/data/textures/TowerBlock1.png b/data/textures/TowerBlock1.png index 4bb9b3594654eea13c60e0fe2fc3a07baca41c82..a920f2c517b048a8381f175c692b250176b56a3a 100644 GIT binary patch delta 67 zcmaFB^?_@Gp#Xb{r>`sfEk;om8JP8(_*ZfnByQGAL1YH>f-LIqu}i0=o4nqI{ diff --git a/data/textures/Trees.png b/data/textures/Trees.png index f64646fce5e5f613a8bd9d570976b26bfd92f6bb..f89a8c1dd60541489b3dd2e9e70bf662fbbc1e9d 100644 GIT binary patch delta 66 zcmaFF`H6Fap#Xb{r>`sfEk;omDb<_b=5Cp&r^Q$|F~>nXKEyxX)y3UaN5R?0(Ki6b Qow!+>MZW6VqJ@uG0O@=d)Bpeg delta 36 scmeyw`G|9Z;Y1hpiH5?Ac@uLS*mV?~eH?uQCLY#id9g)p>B3Je0PLm>W&i*H diff --git a/src/moof/compression.cc b/src/moof/compression.cc new file mode 100644 index 0000000..6362fc0 --- /dev/null +++ b/src/moof/compression.cc @@ -0,0 +1,111 @@ + +/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** +**] All rights reserved. +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +*****************************************************************************/ + +#include +#include +#include + +#include "compression.hh" + +#define ZLIB_BUF_SIZE 262114 + + +namespace moof { + + +void inflate(std::istream& in, std::ostream& out) +{ + char inbuf[ZLIB_BUF_SIZE]; + char outbuf[ZLIB_BUF_SIZE]; + + z_stream zstream; + + zstream.zalloc = Z_NULL; + zstream.zfree = Z_NULL; + zstream.opaque = Z_NULL; + zstream.avail_in = 0; + zstream.next_in = Z_NULL; + + int result = inflateInit2(&zstream, 32 + MAX_WBITS); + if (result != Z_OK) throw std::runtime_error("zlib init error"); + + do { + in.read(inbuf, sizeof(inbuf)); + zstream.next_in = (Bytef*)inbuf; + zstream.avail_in = in.gcount(); + + if (zstream.avail_in == 0) break; + + do { + zstream.next_out = (Bytef*)outbuf; + zstream.avail_out = sizeof(outbuf); + + result = inflate(&zstream, Z_NO_FLUSH); + switch (result) + { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&zstream); + throw std::runtime_error("zlib inflate error"); + case Z_STREAM_ERROR: + throw std::runtime_error("zlib stream error"); + } + + int inflated = sizeof(outbuf) - zstream.avail_out; + out.write(outbuf, inflated); + } + while (zstream.avail_out == 0); + } + while(result != Z_STREAM_END); + + inflateEnd(&zstream); +} + +void inflate(const char* in, size_t size, std::ostream& out) +{ + char buf[ZLIB_BUF_SIZE]; + + z_stream zstream; + zstream.zalloc = Z_NULL; + zstream.zfree = Z_NULL; + zstream.opaque = Z_NULL; + zstream.avail_in = size; + zstream.next_in = (Bytef*)in; + + int result = inflateInit2(&zstream, 32 + MAX_WBITS); + if (result != Z_OK) throw std::runtime_error("zlib init error"); + + do { + zstream.next_out = (Bytef*)buf; + zstream.avail_out = sizeof(buf); + + result = inflate(&zstream, Z_NO_FLUSH); + switch (result) + { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&zstream); + throw std::runtime_error("zlib inflate error"); + case Z_STREAM_ERROR: + throw std::runtime_error("zlib stream error"); + } + + size_t inflated = sizeof(buf) - zstream.avail_out; + out.write(buf, inflated); + } + while (zstream.avail_out == 0); + + inflateEnd(&zstream); +} + + +} // namespace moof + diff --git a/src/moof/compression.hh b/src/moof/compression.hh new file mode 100644 index 0000000..b726088 --- /dev/null +++ b/src/moof/compression.hh @@ -0,0 +1,26 @@ + +/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** +**] All rights reserved. +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +*****************************************************************************/ + +#ifndef _MOOF_COMPRESSION_H_ +#define _MOOF_COMPRESSION_H_ + +#include + + +namespace moof { + + +void inflate(std::istream& in, std::ostream& out); +void inflate(const char* in, size_t size, std::ostream& out); + + +} // namespace moof + +#endif // _MOOF_COMPRESSION_H_ + diff --git a/src/moof/debug.hh b/src/moof/debug.hh index ef42dff..a131ce9 100644 --- a/src/moof/debug.hh +++ b/src/moof/debug.hh @@ -20,7 +20,9 @@ * Debugging facilities. */ - +#define STRINGIZE(X) #X +#define QUOTE_MACRO(X) STRINGIZE(X) +#define FILELINE __FILE__":"QUOTE_MACRO(__LINE__) #undef ASSERT #ifdef NDEBUG @@ -31,9 +33,9 @@ * assertion is false. * \param X test to perform. */ -#define ASSERT(X) if (!(X)) moof::log_error \ - << "false assertion at " << __FILE__ << ":" << __LINE__ << ", " \ - << #X, exit(1) +#define ASSERT(X) \ + if (!(X)) moof::log_error \ + << "false assertion at " << FILELINE << ", " << #X, std::terminate() #endif diff --git a/src/moof/image.cc b/src/moof/image.cc index 77b15c1..c9c0638 100644 --- a/src/moof/image.cc +++ b/src/moof/image.cc @@ -115,7 +115,7 @@ static SDL_Surface* load_png(const std::string& path, texture_attributes& attrib int bpp; png_byte colors; - png_bytepp rows = 0; + png_bytepp rows; png_textp texts = 0; int nutext_s; @@ -170,53 +170,139 @@ static SDL_Surface* load_png(const std::string& path, texture_attributes& attrib png_read_update_info(png.context, png.info); bpp = png_get_bit_depth(png.context, png.info); - channels_ = png_get_channels(png.context, png.info); - depth_ = bpp * channels_; + int channels = png_get_channels(png.context, png.info); + int depth = bpp * channels; // read comments bool texture = false; png_get_text(png.context, png.info, &texts, &nutext_s); for (int i = 0; i < nutext_s; ++i) { - if (strncmp(texts[i].key, "X-Yoink-Texture", 11) == 0) + if (std::string(texts[i].key) == "X-Yoink-Texture") { - set_texture_info(texts[i].text); + attribs.init(texts[i].text); texture = true; break; } } - width_ = png_get_image_width(png.context, png.info); - height_ = png_get_image_height(png.context, png.info); + int width = png_get_image_width(png.context, png.info); + int height = png_get_image_height(png.context, png.info); + int pitch = png_get_rowbytes(png.context, png.info); + char* pixels = new char[height * pitch]; - pitch_ = png_get_rowbytes(png.context, png.info); - pixels_ = new char[width_ * pitch_]; - - rows = new png_bytep[height_]; + rows = new png_bytep[height]; if (texture) { log_debug("texture detected; loading flipped"); - for (int i = 0; i < height_; ++i) + for (int i = 0; i < height; ++i) { - rows[height_-1-i] = (png_bytep)(pixels_ + - i * channels_ * width_); + rows[height-1-i] = (png_bytep)(pixels + + i * channels * width); } } else { log_debug("no texture attributes found"); - for (int i = 0; i < height_; ++i) + for (int i = 0; i < height; ++i) { - rows[i] = (png_bytep)(pixels_ + - i * channels_ * width_); + rows[i] = (png_bytep)(pixels + + i * channels * width); } } png_read_image(png.context, rows); + delete[] rows; + png_read_end(png.context, 0); - // TODO leak - delete[] rows; + SDL_Surface* src = SDL_CreateRGBSurfaceFrom + ( + pixels, + width, + height, + depth, + pitch, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000 +#else + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF +#endif + ); + if (!src) throw std::runtime_error(SDL_GetError()); + return src; +} + +static SDL_Surface* load_bmp(const std::string& path) +{ + return SDL_LoadBMP(path.c_str()); +} + + +#if 0 +static void save_bmp(SDL_Surface* image, const std::string& path) +{ + if (SDL_SaveBMP(image, path.c_str()) != 0) + throw std::runtime_error(SDL_GetError()); +} + + +static void destroy_context(SDL_Surface* context) +{ + if (context->flags & SDL_PREALLOC) delete[] (char*)context->pixels; + SDL_FreeSurface(context); +} +#endif + + +image::image(const std::string& path) : + pixels_(0), + object_(0), + min_filter_(GL_NEAREST), + mag_filter_(GL_NEAREST), + tile_s_(1), + tile_t_(1), + wrap_s_(GL_CLAMP_TO_EDGE), + wrap_t_(GL_CLAMP_TO_EDGE) +{ + std::string ext = stlplus::extension_part(path); + + SDL_Surface* context = 0; + if (ext == "png") + { + texture_attributes attribs; + context = load_png(path, attribs); + pixels_ = (char*)context->pixels; + width_ = context->w; + height_ = context->h; + depth_ = 32; + pitch_ = context->pitch; + channels_ = 4; + min_filter_ = attribs.min_filter; + mag_filter_ = attribs.mag_filter; + tile_s_ = attribs.tile_s; + tile_t_ = attribs.tile_t; + wrap_s_ = attribs.wrap_s; + wrap_t_ = attribs.wrap_t; + postprocess(); + } + else if (ext == "bmp") + { + context = load_bmp(path); + pixels_ = (char*)context->pixels; + width_ = context->w; + height_ = context->h; + depth_ = 32; + pitch_ = context->pitch; + channels_ = 4; + } + // TODO leaking context } image::~image() @@ -226,6 +312,189 @@ image::~image() } +void image::postprocess() +{ + if (1 == tile_s_ && 1 == tile_t_) return; + + SDL_Surface* src = SDL_CreateRGBSurfaceFrom + ( + pixels_, + width_, + height_, + depth_, + pitch_, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000 +#else + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF +#endif + ); + SDL_Surface* dst = SDL_CreateRGBSurface( + SDL_SWSURFACE, + higher_power_of_two(width_), + higher_power_of_two(height_), + depth_, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000 +#else + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF +#endif + ); + ASSERT(src && dst); + + SDL_SetAlpha(src, 0, 128); + SDL_SetAlpha(dst, 0, 128); + + int src_tilew = src->w / tile_s_; + int src_tileh = src->h / tile_t_; + int dst_tilew = dst->w / tile_s_; + int dst_tileh = dst->h / tile_t_; + + for (int t = 0; t < tile_t_; ++t) for (int s = 0; s < tile_s_; ++s) + { + SDL_Rect srcrect; + SDL_Rect dstrect; + srcrect.x = s * src_tilew; + srcrect.y = t * src_tileh; + srcrect.w = src_tilew; + srcrect.h = src_tileh; + dstrect.x = s * dst_tilew + (src_tilew / 2); + dstrect.y = t * dst_tileh + (src_tileh / 2); + log_warning("SRC", srcrect.x, srcrect.y, srcrect.w, srcrect.h); + log_warning("DST", dstrect.x, dstrect.y); + SDL_BlitSurface(src, &srcrect, dst, &dstrect); + + srcrect.x = s * src_tilew; + srcrect.y = t * src_tileh; + srcrect.w = 1; + srcrect.h = src_tileh; + dstrect.y = t * dst_tileh + (src_tileh / 2); + for (int x = s * dst_tilew + (src_tilew / 2) - 1; s * dst_tilew <= x; --x) + { + dstrect.x = x; + SDL_BlitSurface(src, &srcrect, dst, &dstrect); + } + + srcrect.x = (s + 1) * src_tilew - 1; + srcrect.y = t * src_tileh; + srcrect.w = 1; + srcrect.h = src_tileh; + dstrect.y = t * dst_tileh + (src_tileh / 2); + for (int x = (s + 1) * dst_tilew - (src_tilew / 2); x < (s + 1) * dst_tilew; ++x) + { + dstrect.x = x; + SDL_BlitSurface(src, &srcrect, dst, &dstrect); + } + + srcrect.x = s * src_tilew; + srcrect.y = t * src_tileh; + srcrect.w = src_tilew; + srcrect.h = 1; + dstrect.x = s * dst_tilew + (src_tilew / 2); + for (int y = t * dst_tileh + (src_tileh / 2) - 1; t * dst_tileh <= y; --y) + { + dstrect.y = y; + SDL_BlitSurface(src, &srcrect, dst, &dstrect); + } + + srcrect.x = s * src_tilew; + srcrect.y = (t + 1) * src_tileh - 1; + srcrect.w = src_tilew; + srcrect.h = 1; + dstrect.x = s * dst_tilew + (src_tilew / 2); + for (int y = (t + 1) * dst_tileh - (src_tileh / 2); y < (t + 1) * dst_tileh; ++y) + { + dstrect.y = y; + SDL_BlitSurface(src, &srcrect, dst, &dstrect); + } + } + SDL_FreeSurface(src); + + char* pixels = new char[dst->w * dst->pitch]; + SDL_Surface* finaldst = SDL_CreateRGBSurfaceFrom + ( + pixels, + dst->w, + dst->h, + depth_, + dst->pitch, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000 +#else + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF +#endif + ); + SDL_BlitSurface(dst, 0, finaldst, 0); + + //SDL_SaveBMP(dst, (stlplus::basename_part(path) + ".bmp").c_str()); + SDL_FreeSurface(dst); + + width_ = finaldst->w; + height_ = finaldst->h; + pitch_ = finaldst->pitch; + + SDL_FreeSurface(finaldst); + + delete[] pixels_; + pixels_ = pixels; +} + + +void image::fix_uv(std::vector& p) const +{ + vector2 mid(SCALAR(0.0), SCALAR(0.0)); + for (int i = 0; i < p.size(); ++i) + { + mid[0] += p[i][0]; + mid[1] += p[i][1]; + } + mid[0] /= p.size(); + mid[1] /= p.size(); + mid[0] *= tile_s_; + mid[1] *= tile_t_; + mid[0] = std::floor(mid[0]); + mid[1] = std::floor(mid[1]); + log_warning("midpoint:", mid); + scalar s = mid[0]; + scalar t = mid[1]; + + scalar src_width = width_ >> 1; + scalar src_height = height_ >> 1; + int src_tilew = src_width / tile_s_; + int src_tileh = src_height / tile_t_; + int dst_tilew = width_ / tile_s_; + int dst_tileh = height_ / tile_t_; + + for (int i = 0; i < p.size(); ++i) + { + //scalar s = p[i][0] * src_width; + scalar x = s * dst_tilew + (src_tilew / 2) + (p[i][0] * src_width - s * src_tilew); + p[i][0] = x / width_; + //scalar t = p[i][1] * src_height; + scalar y = t * dst_tileh + (src_tileh / 2) + (p[i][1] * src_height - t * src_tileh);; + p[i][1] = y / height_; + } +} + + void image::set_as_icon() const { backend backend; @@ -276,7 +545,7 @@ bool image::tile_coordinates(int index, scalar coords[8]) const void image::bind() const { - ASSERT(video::current() && "should have a video context set"); + ASSERT(video::ready() && "should have a video context set"); if (object_ == 0) { @@ -291,7 +560,7 @@ void image::bind() const void image::reset_binding() { - ASSERT(video::current() && "should have a video context set"); + ASSERT(video::ready() && "should have a video context set"); glBindTexture(GL_TEXTURE_2D, 0); global_object_ = 0; @@ -364,40 +633,8 @@ void image::set_properties() const glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_); } -void image::set_texture_info(const std::string& info) -{ - script script; - log::import(script); - - script::slot g = script.globals(); - g.set_field("CLAMP", GL_CLAMP); - g.set_field("REPEAT", GL_REPEAT); - g.set_field("LINEAR", GL_LINEAR); - g.set_field("NEAREST", GL_NEAREST); - g.set_field("LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR); - g.set_field("LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST); - g.set_field("NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR); - g.set_field("NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST); - - if (script.do_string(info) != script::success) - { - std::string str; - script[-1].get(str); - log_warning(str); - } - else - { - log_info("loading texture information..."); - - script::slot globals = script.globals(); - globals.get(min_filter_, "min_filter"); - globals.get(mag_filter_, "mag_filter"); - globals.get(tile_s_, "tile_s"); - globals.get(tile_t_, "tile_t"); - globals.get(wrap_s_, "wrap_s"); - globals.get(wrap_t_, "wrap_t"); - } -} + +unsigned image::global_object_ = 0; } // namespace moof diff --git a/src/moof/image.hh b/src/moof/image.hh index 4dee19f..89a7faa 100644 --- a/src/moof/image.hh +++ b/src/moof/image.hh @@ -59,11 +59,6 @@ public: return channels_; } - std::string comment() const - { - return comment_; - } - const char* pixels() const { return pixels_; @@ -76,26 +71,28 @@ public: * are indexed start with zero as the top-left tile and moving across, * then down. * \param index The tile index. - * \param coords An array of scalars where the texture coordinates will - * be stored after this call. The first coordinate (u,v) will be in - * the first two places and so on until all four coordinates are + * \param coords An array of scalars where the texture coordinates + * will be stored after this call. The first coordinate (u,v) will be + * in the first two places and so on until all four coordinates are * stored, therefore requiring enough room for an array of eight - * scalars. The winding of the coordinates is always counter-clockwise - * (the GL default). + * scalars. The winding of the coordinates is always + * counter-clockwise (the GL default). * \return True if index is valid, false otherwise. */ bool tile_coordinates(int index, scalar coords[8]) const; + void fix_uv(std::vector& p) const; + void bind() const; static void reset_binding(); private: + void postprocess(); void upload_to_gl() const; void unload_from_gl() const; void context_recreated(); void set_properties() const; - void set_texture_info(const std::string& info); char* pixels_; @@ -108,8 +105,6 @@ private: int pitch_; int channels_; - std::string comment_; - unsigned min_filter_; unsigned mag_filter_; int tile_s_; diff --git a/src/moof/mesh.cc b/src/moof/mesh.cc index 32550f7..eac6ef9 100644 --- a/src/moof/mesh.cc +++ b/src/moof/mesh.cc @@ -16,21 +16,21 @@ #include #include +#include "compression.hh" #include "debug.hh" #include "log.hh" #include "mesh.hh" #include "opengl.hh" -// TODO: this file needs to be cleaned up - #define AC3D_FORMAT_VERSION 0x0b -#define ZLIB_BUF_SIZE 262114 namespace moof { MOOF_REGISTER_RESOURCE(mesh, ac, models); +MOOF_REGISTER_RESOURCE(mesh, acz, models); + static std::string read_string(std::istream& stream) { @@ -74,9 +74,9 @@ static int read_hex(std::istream& stream) static vector2 read_pair(std::istream& stream) { - vector2 triplet; - stream >> triplet[0] >> triplet[1]; - return triplet; + vector2 pair; + stream >> pair[0] >> pair[1]; + return pair; } static vector3 read_triplet(std::istream& stream) @@ -94,74 +94,47 @@ static vector4 read_color(std::istream& stream) return color; } -void mesh::import(std::istream& stream) + +static inline void throw_invalid_atom(const std::string& atom) { - std::string atom; - object_ptr obj; - std::stack kids; + throw std::runtime_error("unexpected atom: " + atom); +} + +void mesh::load(std::istream& stream) +{ // read and verify the AC3D header - { - char magic[5]; - unsigned version = 0; + char magic[5]; + unsigned version = 0; - stream.get(magic, sizeof(magic)); - if (!stream || strncmp(magic, "AC3D", 4) != 0) - { - throw std::runtime_error("invalid mesh header"); - } + stream.get(magic, sizeof(magic)); + if (!stream || strncmp(magic, "AC3D", 4) != 0) + { + throw std::runtime_error("invalid mesh header"); + } - version = read_hex(stream); - if (version > AC3D_FORMAT_VERSION) - { - throw std::runtime_error("wrong mesh file format version"); - } + version = read_hex(stream); + if (version > AC3D_FORMAT_VERSION) + { + throw std::runtime_error("wrong mesh file format version"); } + std::string atom; + object_ptr obj; + std::stack kids; + while (stream) { stream >> atom; if (!stream) break; - if (atom == "MATERIAL") + if (atom == "OBJECT") { - materials_.push_back(material(read_string(stream))); - - stream >> atom; - materials_.back().diffuse = read_color(stream); - stream >> atom; - materials_.back().ambient = read_color(stream); - stream >> atom; - materials_.back().emissive = read_color(stream); - stream >> atom; - materials_.back().specular = read_color(stream); - - stream >> atom >> materials_.back().shininess; - stream >> atom >> materials_.back().diffuse[3]; - materials_.back().diffuse[3] = SCALAR(1.0) - - materials_.back().diffuse[3]; + obj = load_object(stream, obj); } - else if (atom == "OBJECT") + else if (atom == "MATERIAL") { - stream >> atom; - if (atom != "world" && atom != "group" && atom != "poly") - { - throw std::runtime_error("unexpected object type " + atom); - } - - object_ptr newObj = object::alloc(*this); - - if (obj) - { - obj->kids.push_back(newObj); - newObj->parent = obj; - } - else - { - objects_.push_back(newObj); - } - - obj = newObj; + load_material(stream); } else if (atom == "name") { @@ -171,7 +144,10 @@ void mesh::import(std::istream& stream) object_ptr parent = obj->parent.lock(); if (parent) parent->kids_byname.insert(std::make_pair(obj->name, obj)); } - else throw std::runtime_error("unexpected atom: " + atom); + else + { + throw_invalid_atom(atom); + } } else if (atom == "data") { @@ -185,7 +161,7 @@ void mesh::import(std::istream& stream) else if (atom == "texrep") { if (obj) obj->texrep = read_pair(stream); - else throw std::runtime_error("unexpected atom: " + atom); + else throw_invalid_atom(atom); } else if (atom == "rot") { @@ -200,11 +176,11 @@ void mesh::import(std::istream& stream) else if (atom == "url") { if (obj) std::getline(stream, obj->url); - else throw std::runtime_error("unexpected atom: " + atom); + else throw_invalid_atom(atom); } else if (atom == "numvert") { - if (!obj) throw std::runtime_error("unexpected atom: " + atom); + if (!obj) throw_invalid_atom(atom); int numvert = 0; stream >> numvert; @@ -216,7 +192,7 @@ void mesh::import(std::istream& stream) } else if (atom == "numsurf") { - if (!obj) throw std::runtime_error("unexpected atom: " + atom); + if (!obj) throw_invalid_atom(atom); int numsurf = 0; stream >> numsurf; @@ -224,119 +200,19 @@ void mesh::import(std::istream& stream) for (int i = 0; i < numsurf; ++i) { stream >> atom; - if (atom != "SURF") throw std::runtime_error("uh oh"); - - read_hex(stream); - - int material = 0; - stream >> atom; - if (atom == "mat") stream >> material >> atom; - - if (atom != "refs") - { - throw std::runtime_error("blaaaaaaaahhh!!"); - } - - int numrefs = 0; - stream >> numrefs; - ASSERT(numrefs >= 3); - - if ((int)obj->faces.size() <= material) - { - obj->faces.resize(material + 1); - } - material_group& face = obj->faces[material]; - - unsigned vert; - stream >> vert; - vector2 uv = read_pair(stream); - if (vert < face.triangles_uv.size()) - { - if (uv != face.triangles_uv[vert]) - { - obj->verts.push_back(obj->verts[vert]); - face.triangles_uv.resize(obj->verts.size()); - vert = obj->verts.size() - 1; - } - } - else face.triangles_uv.resize(vert + 1); - face.triangles_uv[vert] = uv; - face.triangles.push_back(vert); - - unsigned first = vert; - - stream >> vert; - uv = read_pair(stream); - if (vert < face.triangles_uv.size()) - { - if (uv != face.triangles_uv[vert]) - { - obj->verts.push_back(obj->verts[vert]); - face.triangles_uv.resize(obj->verts.size()); - vert = obj->verts.size() - 1; - } - } - else face.triangles_uv.resize(vert + 1); - face.triangles_uv[vert] = uv; - face.triangles.push_back(vert); - - stream >> vert; - uv = read_pair(stream); - if (vert < face.triangles_uv.size()) - { - if (uv != face.triangles_uv[vert]) - { - obj->verts.push_back(obj->verts[vert]); - face.triangles_uv.resize(obj->verts.size()); - vert = obj->verts.size() - 1; - } - } - else face.triangles_uv.resize(vert + 1); - face.triangles_uv[vert] = uv; - face.triangles.push_back(vert); - - unsigned last = vert; - - for (int j = 3; j < numrefs; ++j) - { - face.triangles.push_back(first); - face.triangles.push_back(last); - - stream >> vert; - uv = read_pair(stream); - if (vert < face.triangles_uv.size()) - { - if (uv != face.triangles_uv[vert]) - { - obj->verts.push_back(obj->verts[vert]); - face.triangles_uv.resize(obj->verts.size()); - vert = obj->verts.size() - 1; - } - } - else face.triangles_uv.resize(vert + 1); - face.triangles_uv[vert] = uv; - face.triangles.push_back(vert); - - last = face.triangles.back(); - } + if (atom != "SURF") throw_invalid_atom(atom); + load_surface(stream, obj); } + } else if (atom == "kids") { - //while (0 < kids.size()) - //{ - //if (--kids.top() <= 0) - //{ - //ASSERT(obj && "should be an object"); - //obj = obj->parent; - //kids.pop(); - //} - //else break; - //} - int numkids = 0; stream >> numkids; - if (0 < numkids) kids.push(numkids); + if (0 < numkids) + { + kids.push(numkids); + } else { if (0 < kids.size() && 0 < --kids.top()) kids.pop(); @@ -347,29 +223,188 @@ void mesh::import(std::istream& stream) while (stream); } -//unsigned mesh::read_vertex_line(std::istream& stream) -//{ - //unsigned vert; - //stream >> vert; - //vector2 uv = read_pair(stream); - //if (vert < face.triangles_uv.size()) - //{ - //if (uv != face.triangles_uv[vert]) - //{ - //obj->verts.push_back(obj->verts[vert]); - //face.triangles_uv.resize(obj->verts.size()); - //vert = obj->verts.size() - 1; - //} - //} - //else face.triangles_uv.resize(vert + 1); - //face.triangles_uv[vert] = uv; - //face.triangles.push_back(vert); -//} + +void mesh::load_material(std::istream& stream) +{ + materials_.push_back(material(read_string(stream))); + + std::string atom; + stream >> atom; + materials_.back().diffuse = read_color(stream); + stream >> atom; + materials_.back().ambient = read_color(stream); + stream >> atom; + materials_.back().emissive = read_color(stream); + stream >> atom; + materials_.back().specular = read_color(stream); + + stream >> atom >> materials_.back().shininess; + stream >> atom >> materials_.back().diffuse[3]; + materials_.back().diffuse[3] = SCALAR(1.0) - materials_.back().diffuse[3]; +} + +mesh::object_ptr mesh::load_object(std::istream& stream, object_ptr parent) +{ + std::string atom; + stream >> atom; + if (atom != "world" && atom != "group" && atom != "poly") + { + throw_invalid_atom(atom); + } + + object_ptr obj = object::alloc(*this); + + if (parent) + { + parent->kids.push_back(obj); + obj->parent = parent; + } + else + { + objects_.push_back(obj); + } + + return obj; +} + +void mesh::load_surface(std::istream& stream, object_ptr obj) +{ + std::string atom; + read_hex(stream); + + int material = 0; + stream >> atom; + if (atom == "mat") stream >> material >> atom; + if (atom != "refs") throw_invalid_atom(atom); + + int numrefs = 0; + stream >> numrefs; + ASSERT(numrefs >= 3); + + if ((int)obj->faces.size() <= material) obj->faces.resize(material + 1); + material_group& face = obj->faces[material]; + + std::vector verts(numrefs); + std::vector uv(numrefs); + + for (int i = 0; i < numrefs; ++i) + { + stream >> verts[i]; + uv[i] = read_pair(stream); + } + + // translate texture coordinates + if (obj->texture) obj->texture->fix_uv(uv); + // TODO why isn't texture always defined at this point? + + for (int i = 0; i < numrefs; ++i) + { + scalar vert = verts[i]; + vector2 texcoord = uv[i]; + if (vert < face.triangles_uv.size()) + { + if (texcoord != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = texcoord; + verts[i] = vert; + } + + face.triangles.push_back(verts[0]); + face.triangles.push_back(verts[1]); + face.triangles.push_back(verts[2]); + for (int i = 3; i < numrefs; ++i) + { + face.triangles.push_back(verts[0]); + face.triangles.push_back(verts[i-1]); + face.triangles.push_back(verts[i]); + } + +#if 0 + unsigned vert; + stream >> vert; + vector2 uv = read_pair(stream); + if (vert < face.triangles_uv.size()) + { + if (uv != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = uv; + face.triangles.push_back(vert); + + unsigned first = vert; + + stream >> vert; + uv = read_pair(stream); + if (vert < face.triangles_uv.size()) + { + if (uv != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = uv; + face.triangles.push_back(vert); + + stream >> vert; + uv = read_pair(stream); + if (vert < face.triangles_uv.size()) + { + if (uv != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = uv; + face.triangles.push_back(vert); + + unsigned last = vert; + + for (int j = 3; j < numrefs; ++j) + { + face.triangles.push_back(first); + face.triangles.push_back(last); + + stream >> vert; + uv = read_pair(stream); + if (vert < face.triangles_uv.size()) + { + if (uv != face.triangles_uv[vert]) + { + obj->verts.push_back(obj->verts[vert]); + face.triangles_uv.resize(obj->verts.size()); + vert = obj->verts.size() - 1; + } + } + else face.triangles_uv.resize(vert + 1); + face.triangles_uv[vert] = uv; + face.triangles.push_back(vert); + + last = face.triangles.back(); + } +#endif +} + mesh::mesh(const std::string& path) { - std::ifstream file(path.c_str(), std::ifstream::in | - std::ifstream::binary); + std::ifstream file(path.c_str(), std::ios::binary); if (!file) throw std::runtime_error("cannot find mesh file"); // if we can read the header, the file isn't compressed @@ -379,61 +414,15 @@ mesh::mesh(const std::string& path) { log_info("text mesh detected"); file.seekg(std::ios::beg); - import(file); + load(file); } else { - log_info("compressed mesh detected"); + log_info("decompressing mesh..."); file.seekg(std::ios::beg); - std::stringstream stream; - char in[ZLIB_BUF_SIZE]; - char out[ZLIB_BUF_SIZE]; - - z_stream zstream; - - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.avail_in = 0; - zstream.next_in = Z_NULL; - - int result = inflateInit2(&zstream, 32+MAX_WBITS); - if (result != Z_OK) - throw std::runtime_error("zlib init error"); - - do { - file.read(in, sizeof(in)); - zstream.next_in = (Bytef*)in; - zstream.avail_in = file.gcount(); - - if (zstream.avail_in == 0) break; - - do { - zstream.next_out = (Bytef*)out; - zstream.avail_out = sizeof(out); - - result = inflate(&zstream, Z_NO_FLUSH); - switch (result) - { - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&zstream); - throw std::runtime_error("zlib inflate error"); - case Z_STREAM_ERROR: - throw std::runtime_error("zlib stream error"); - } - - int inflated = sizeof(out) - zstream.avail_out; - stream.write(out, inflated); - } - while (zstream.avail_out == 0); - } - while(result != Z_STREAM_END); - - inflateEnd(&zstream); - import(stream); + inflate(file, stream); + load(stream); } } @@ -465,6 +454,7 @@ void mesh::set_material(const material& material) const glMaterial(GL_FRONT, GL_SHININESS, material.shininess); } + void mesh::object::draw(scalar alpha, bool recurse) const { glVertexPointer(verts); @@ -499,23 +489,6 @@ void mesh::object::draw(scalar alpha, bool recurse) const } } -//class mesh_resource_loader -//{ -//public: - - //mesh_resource_loader() - //{ - //resource::register_type("ac", "models"); - //} - - //~mesh_resource_loader() - //{ - //resource::unregister_type("ac"); - //} -//}; - -//static mesh_resource_loader loader; - } // namespace moof diff --git a/src/moof/mesh.hh b/src/moof/mesh.hh index 3f0dc24..5c9c343 100644 --- a/src/moof/mesh.hh +++ b/src/moof/mesh.hh @@ -114,7 +114,11 @@ public: private: - void import(std::istream& stream); + void load(std::istream& stream); + + void load_material(std::istream& stream); + object_ptr load_object(std::istream& stream, object_ptr parent); + void load_surface(std::istream& stream, object_ptr obj); std::vector materials_; std::vector objects_; diff --git a/src/moof/video.cc b/src/moof/video.cc index 30de984..c4e8fd8 100644 --- a/src/moof/video.cc +++ b/src/moof/video.cc @@ -97,9 +97,9 @@ void video::set_opengl_attributes() SDL_GL_SetAttribute(SDL_GL_STEREO, attributes_.is_stereo); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, - attributes_.multisample_buffers); + 0 < attributes_.multisamples); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, - attributes_.multisample_samples); + attributes_.multisamples); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, attributes_.is_swap_control); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, @@ -124,7 +124,7 @@ void video::mode(const int mode[3]) if (context_) SDL_FreeSurface(context_); context_ = SDL_SetVideoMode(mode[0], mode[1], mode[2], - flags_); + SDL_OPENGL | flags_); if (context_) { @@ -139,7 +139,7 @@ void video::mode(const int mode[3]) } else { - throw std::runtime_error("bad video mode attempted"); + throw std::runtime_error(SDL_GetError()); } } } @@ -322,8 +322,7 @@ video::attributes::attributes(const settings& settings) if (accum.size() > 3) accumulator_buffer[3] = accum[3]; settings.get("stereo", is_stereo); - settings.get("multiesamplebuffers", multisample_buffers); - settings.get("multiesamplesamples", multisample_samples); + settings.get("multisamples", multisamples); settings.get("swapcontrol", is_swap_control); settings.get("hardwareonly", is_hardware_only); @@ -380,8 +379,7 @@ void video::attributes::init() accumulator_buffer[2] = 0; accumulator_buffer[3] = 0; is_stereo = false; - multisample_buffers = 0; - multisample_samples = 0; + multisamples = 0; is_swap_control = false; is_hardware_only = false; mode[0] = 640; diff --git a/src/moof/video.hh b/src/moof/video.hh index 9ec795f..1349b67 100644 --- a/src/moof/video.hh +++ b/src/moof/video.hh @@ -47,8 +47,7 @@ public: int stencil_buffer; int accumulator_buffer[4]; // rgba bool is_stereo; - int multisample_buffers; - int multisample_samples; + int multisamples; bool is_swap_control; bool is_hardware_only; int mode[3]; // width, height, bpp @@ -118,7 +117,16 @@ public: /** * Get the current video context where draw commands are sent. */ - static video* current() + static video& current() + { + return *current_; + } + + /** + * Get whether or not a video context is in place and is ready to + * received drawing commands. + */ + static bool ready() { return current_; } -- 2.43.0