--- /dev/null
+
+/*] 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 <iostream>
+#include <stdexcept>
+#include <zlib.h>
+
+#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
+
--- /dev/null
+
+/*] 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 <iostream>
+
+
+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_
+
* Debugging facilities.
*/
-
+#define STRINGIZE(X) #X
+#define QUOTE_MACRO(X) STRINGIZE(X)
+#define FILELINE __FILE__":"QUOTE_MACRO(__LINE__)
#undef ASSERT
#ifdef NDEBUG
* 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
int bpp;
png_byte colors;
- png_bytepp rows = 0;
+ png_bytepp rows;
png_textp texts = 0;
int nutext_s;
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()
}
+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<vector2>& 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;
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)
{
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;
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
return channels_;
}
- std::string comment() const
- {
- return comment_;
- }
-
const char* pixels() const
{
return pixels_;
* 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<vector2>& 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_;
int pitch_;
int channels_;
- std::string comment_;
-
unsigned min_filter_;
unsigned mag_filter_;
int tile_s_;
#include <boost/algorithm/string/trim.hpp>
#include <zlib.h>
+#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)
{
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)
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<int> 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<int> 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")
{
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")
{
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")
{
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;
}
else if (atom == "numsurf")
{
- if (!obj) throw std::runtime_error("unexpected atom: " + atom);
+ if (!obj) throw_invalid_atom(atom);
int numsurf = 0;
stream >> numsurf;
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();
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<unsigned> verts(numrefs);
+ std::vector<vector2> 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
{
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);
}
}
glMaterial(GL_FRONT, GL_SHININESS, material.shininess);
}
+
void mesh::object::draw(scalar alpha, bool recurse) const
{
glVertexPointer(verts);
}
}
-//class mesh_resource_loader
-//{
-//public:
-
- //mesh_resource_loader()
- //{
- //resource::register_type<mesh>("ac", "models");
- //}
-
- //~mesh_resource_loader()
- //{
- //resource::unregister_type("ac");
- //}
-//};
-
-//static mesh_resource_loader loader;
-
} // namespace moof
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<material> materials_;
std::vector<object_ptr> objects_;
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,
if (context_) SDL_FreeSurface(context_);
context_ = SDL_SetVideoMode(mode[0], mode[1], mode[2],
- flags_);
+ SDL_OPENGL | flags_);
if (context_)
{
}
else
{
- throw std::runtime_error("bad video mode attempted");
+ throw std::runtime_error(SDL_GetError());
}
}
}
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);
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;
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
/**
* 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_;
}