description "C++ wrappers for OpenGL";
version "0.1";
+ feature "devil" "Include DevIL support for loading image files";
+
// A bit of a hack until I get something better in builder
if "arch!=win32"
{
};
};
require "mspdatafile";
- require "devil";
- build_info
+ if "with_devil"
{
- library "ILU";
+ require "devil";
+ build_info
+ {
+ library "ILU";
+ };
};
library "mspgl"
--- /dev/null
+#!/usr/bin/python
+
+# $Id$
+
+import Image
+import sys
+import os
+
+def escape(str):
+ result=""
+ for c in str:
+ if c=='"':
+ result+='\\"'
+ elif c=='\\':
+ result+='\\\\'
+ elif ord(c)<0x20:
+ result+="\\%03o"%ord(c)
+ else:
+ result+=c
+ return result;
+
+img=Image.open(sys.argv[1])
+out=file(os.path.splitext(sys.argv[1])[0]+".tex", "w")
+fmt="".join(img.getbands())
+if fmt=="LA":
+ fmt="LUMINANCE_ALPHA"
+elif fmt=="L":
+ fmt="LUMINANCE"
+out.write("storage %s %d %d 0;\n"%(fmt, img.size[0], img.size[1]))
+out.write("min_filter LINEAR;\n")
+out.write("raw_data \"")
+data=list(img.getdata())
+for y in range(img.size[1]):
+ i=(img.size[1]-1-y)*img.size[0]
+ out.write(escape("".join(["".join([chr(v) for v in p]) for p in data[i:i+img.size[0]]])))
+out.write("\";\n")
#include "gl.h"
#include "font.h"
+#include "primitivetype.h"
#include "texture2d.h"
using namespace std;
tex(0),
default_size(1),
ascent(1),
- descent(0),
- varray((TEXCOORD2, VERTEX2))
+ descent(0)
{ }
void Font::set_texture(const Texture2D &t)
glyph.off_x=ox;
glyph.off_y=oy;
glyph.advance=adv;
- glyph.index=glyphs.size();
glyphs.insert(GlyphMap::value_type(code, glyph));
-
- RefPtr<VertexArrayBuilder> va_builder=varray.modify();
- create_glyph_vertices(glyph, *va_builder);
}
float Font::get_string_width(const string &str, Codecs::Decoder &dec) const
void Font::draw_string(const string &str, Codecs::Decoder &dec) const
{
- prepare_render();
+ tex->bind();
+ VertexArray va((TEXCOORD2, VERTEX2));
+ va.reserve(str.size()*4);
+ RefPtr<VertexArrayBuilder> vab=va.modify();
+ float x=0;
+ unsigned count=0;
for(string::const_iterator i=str.begin(); i!=str.end();)
- draw_glyph(dec.decode_char(str, i));
-
- glPopMatrix();
-}
-
-void Font::create_glyph_vertices()
-{
- varray.clear();
- RefPtr<VertexArrayBuilder> va_builder=varray.modify();
-
- unsigned n=0;
- for(GlyphMap::iterator i=glyphs.begin(); i!=glyphs.end(); ++i, ++n)
{
- i->second.index=n;
- create_glyph_vertices(i->second, *va_builder);
- }
-}
-
-void Font::create_glyph_vertices(const Glyph &glyph, VertexArrayBuilder &va_builder)
-{
- va_builder.texcoord(glyph.x1, glyph.y1);
- va_builder.vertex(glyph.off_x, glyph.off_y);
- va_builder.texcoord(glyph.x2, glyph.y1);
- va_builder.vertex(glyph.off_x+glyph.w, glyph.off_y);
- va_builder.texcoord(glyph.x2, glyph.y2);
- va_builder.vertex(glyph.off_x+glyph.w, glyph.off_y+glyph.h);
- va_builder.texcoord(glyph.x1, glyph.y2);
- va_builder.vertex(glyph.off_x, glyph.off_y+glyph.h);
-}
+ GlyphMap::const_iterator j=glyphs.find(dec.decode_char(str, i));
+ if(j==glyphs.end())
+ continue;
-void Font::prepare_render() const
-{
- tex->bind();
- varray.apply();
- glPushMatrix();
+ create_glyph_vertices(j->second, *vab, x);
+ x+=j->second.advance;
+ count+=4;
+ }
+ vab=0;
+ va.apply();
+ glDrawArrays(QUADS, 0, count);
}
-void Font::draw_glyph(unsigned code) const
+void Font::create_glyph_vertices(const Glyph &glyph, VertexBuilder &vbuilder, float x) const
{
- GlyphMap::const_iterator i=glyphs.find(code);
- if(i==glyphs.end())
- return;
-
- const Glyph &glyph=i->second;
- (void)glyph;
-
- glDrawArrays(GL_QUADS, i->second.index*4, 4);
-
- glTranslatef(i->second.advance, 0, 0);
+ vbuilder.texcoord(glyph.x1, glyph.y1);
+ vbuilder.vertex(x+glyph.off_x, glyph.off_y);
+ vbuilder.texcoord(glyph.x2, glyph.y1);
+ vbuilder.vertex(x+glyph.off_x+glyph.w, glyph.off_y);
+ vbuilder.texcoord(glyph.x2, glyph.y2);
+ vbuilder.vertex(x+glyph.off_x+glyph.w, glyph.off_y+glyph.h);
+ vbuilder.texcoord(glyph.x1, glyph.y2);
+ vbuilder.vertex(x+glyph.off_x, glyph.off_y+glyph.h);
}
float Font::get_glyph_advance(unsigned code) const
return *coll;
}
-Font::Loader::~Loader()
-{
- font.create_glyph_vertices();
-}
-
void Font::Loader::init()
{
add("default_size", &Font::default_size);
Loader(Font &);
Loader(Font &, DataFile::Collection &);
- ~Loader();
Font &get_object() { return font; }
DataFile::Collection &get_collection();
private:
float w,h;
float off_x, off_y;
float advance;
- unsigned index;
};
typedef std::map<unsigned, Glyph> GlyphMap;
float ascent;
float descent;
GlyphMap glyphs;
- VertexArray varray;
- void create_glyph_vertices();
- void create_glyph_vertices(const Glyph &, VertexArrayBuilder &);
- void prepare_render() const;
- void draw_glyph(unsigned) const;
+ void create_glyph_vertices(const Glyph &, VertexBuilder &, float) const;
float get_glyph_advance(unsigned) const;
};
Distributed under the LGPL
*/
+#ifdef WITH_DEVIL
#include <IL/il.h>
+#endif
#include <msp/core/except.h>
#include "ilwrap.h"
Image::Image()
{
+#ifdef WITH_DEVIL
static bool init_done=false;
if(!init_done)
}
ilGenImages(1, &id);
+#else
+ throw Exception("DevIL support not compiled in");
+#endif
}
Image::~Image()
{
+#ifdef WITH_DEVIL
ilDeleteImages(1, &id);
+#endif
}
void Image::load_file(const string &fn)
{
+#ifdef WITH_DEVIL
ilBindImage(id);
if(!ilLoadImage(const_cast<char *>(fn.c_str())))
throw Exception("Error loading image "+fn);
+#else
+ (void)fn;
+#endif
}
void Image::load_lump(const void *data, unsigned size)
{
+#ifdef WITH_DEVIL
ilBindImage(id);
if(!ilLoadL(IL_TYPE_UNKNOWN, const_cast<void *>(data), size))
throw Exception("Error loading image from lump");
+#else
+ (void)data; (void)size;
+#endif
}
PixelFormat Image::get_format() const
{
+#ifdef WITH_DEVIL
switch(ilGetInteger(IL_IMAGE_FORMAT))
{
case IL_COLOR_INDEX: return COLOR_INDEX;
case IL_BGRA: return BGRA;
default: throw InvalidParameterValue("Unknown pixel format in image");
}
+#else
+ return RGB;
+#endif
}
unsigned Image::get_width() const
{
+#ifdef WITH_DEVIL
return ilGetInteger(IL_IMAGE_WIDTH);
+#else
+ return 0;
+#endif
}
unsigned Image::get_height() const
{
+#ifdef WITH_DEVIL
return ilGetInteger(IL_IMAGE_HEIGHT);
+#else
+ return 0;
+#endif
}
const void *Image::get_data() const
{
+#ifdef WITH_DEVIL
return ilGetData();
+#else
+ return 0;
+#endif
}
} // namespace GL
namespace GL {
Immediate::Immediate(VertexFormat f):
- array(f),
- in_batch(false),
- n_vertices(0)
+ PrimitiveBuilder(array),
+ array(f)
{ }
-void Immediate::begin(PrimitiveType t)
+void Immediate::end_()
{
- type=t;
- in_batch=true;
- n_vertices=0;
- builder=array.modify();
-}
-
-void Immediate::end()
-{
- builder=0;
-
array.apply();
- glDrawArrays(type, 0, n_vertices);
+ glDrawArrays(type, 0, array.size());
array.clear();
- in_batch=false;
-}
-
-void Immediate::vertex_(float x, float y, float z, float w)
-{
- if(!in_batch)
- throw InvalidState("Vertex specification not between begin and end");
-
- builder->texcoord(ts, tt, tr,tq);
- builder->color(cr, cg, cb, ca);
- builder->normal(nx, ny, nz);
- builder->vertex(x, y, z, w);
-
- ++n_vertices;
}
} // namespace GL
#ifndef MSP_GL_IMMEDIATE_H_
#define MSP_GL_IMMEDIATE_H_
-#include "primitivetype.h"
-#include "vertexarray.h"
-#include "vertexbuilder.h"
+#include "primitivebuilder.h"
namespace Msp {
namespace GL {
are not drawn as they are specified. Instead, they are accumulated in a
VertexArray and drawn when end() is called.
*/
-class Immediate: public VertexBuilder
+class Immediate: public PrimitiveBuilder
{
-public:
- Immediate(VertexFormat);
- void begin(PrimitiveType);
- void end();
private:
VertexArray array;
- RefPtr<VertexArrayBuilder> builder;
- PrimitiveType type;
- bool in_batch;
- unsigned n_vertices;
- virtual void vertex_(float, float, float, float);
+public:
+ Immediate(VertexFormat);
+private:
+ virtual void begin_() { }
+ virtual void end_();
};
} // namespace GL
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "pixelformat.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+istream &operator>>(istream &in, PixelFormat &fmt)
+{
+ string word;
+
+ in>>word;
+ if(word=="COLOR_INDEX")
+ fmt=COLOR_INDEX;
+ else if(word=="STENCIL_INDEX")
+ fmt=STENCIL_INDEX;
+ else if(word=="DEPTH_COMPONENT")
+ fmt=DEPTH_COMPONENT;
+ else if(word=="RED")
+ fmt=RED;
+ else if(word=="GREEN")
+ fmt=GREEN;
+ else if(word=="BLUE")
+ fmt=BLUE;
+ else if(word=="ALPHA")
+ fmt=ALPHA;
+ else if(word=="RGB")
+ fmt=RGB;
+ else if(word=="RGBA")
+ fmt=RGBA;
+ else if(word=="BGR")
+ fmt=BGR;
+ else if(word=="BGRA")
+ fmt=BGRA;
+ else if(word=="LUMINANCE")
+ fmt=LUMINANCE;
+ else if(word=="LUMINANCE_ALPHA")
+ fmt=LUMINANCE_ALPHA;
+ else
+ in.setstate(ios_base::failbit);
+
+ return in;
+}
+
+} // namespace GL
+} // namespace Msp
#ifndef MSP_GL_PIXELFORMAT_H_
#define MSP_GL_PIXELFORMAT_H_
+#include <istream>
#include "gl.h"
namespace Msp {
LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA
};
+std::istream &operator>>(std::istream &, PixelFormat &);
+
} // namespace GL
} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "primitivebuilder.h"
+
+namespace Msp {
+namespace GL {
+
+PrimitiveBuilder::PrimitiveBuilder(VertexArray &a):
+ array(a),
+ in_batch(false)
+{ }
+
+void PrimitiveBuilder::begin(PrimitiveType t)
+{
+ if(in_batch)
+ throw InvalidState("begin() already called");
+
+ type=t;
+ in_batch=true;
+ builder=array.modify();
+
+ begin_();
+}
+
+void PrimitiveBuilder::end()
+{
+ if(in_batch)
+ throw InvalidState("end() called without begin()");
+
+ builder=0;
+ in_batch=false;
+
+ end_();
+}
+
+PrimitiveType PrimitiveBuilder::get_type() const
+{
+ if(!in_batch)
+ throw InvalidState("Not between begin() and end()");
+ return type;
+}
+
+void PrimitiveBuilder::vertex_(float x, float y, float z, float w)
+{
+ if(!in_batch)
+ throw InvalidState("Vertex specification not between begin() and end()");
+
+ builder->texcoord(ts, tt, tr,tq);
+ builder->color(cr, cg, cb, ca);
+ builder->normal(nx, ny, nz);
+ builder->vertex(x, y, z, w);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GL_PRIMITIVEBUILDER_H_
+#define MSP_GL_PRIMITIVEBUILDER_H_
+
+#include "primitivetype.h"
+#include "vertexarray.h"
+#include "vertexbuilder.h"
+
+namespace Msp {
+namespace GL {
+
+class VertexArray;
+class VertexArrayBuilder;
+
+/**
+Base class for primitive builders. This is derived from VertexBuilder and adds
+begin() and end() functions for specifying batches of primitives instead of
+just vertices.
+*/
+class PrimitiveBuilder: public VertexBuilder
+{
+protected:
+ VertexArray &array;
+ RefPtr<VertexArrayBuilder> builder;
+ PrimitiveType type;
+ bool in_batch;
+
+ PrimitiveBuilder(VertexArray &);
+public:
+ void begin(PrimitiveType);
+ void end();
+ PrimitiveType get_type() const;
+protected:
+ virtual void vertex_(float, float, float, float);
+ virtual void begin_() =0;
+ virtual void end_() =0;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
Texture::Loader(t)
{
add("image_data", &Loader::image_data);
+ add("raw_data", &Loader::raw_data);
+ add("storage", &Loader::storage);
}
void Texture2D::Loader::image_data(const string &data)
static_cast<Texture2D &>(tex).image(img);
}
+void Texture2D::Loader::raw_data(const string &data)
+{
+ Texture2D &t2d=static_cast<Texture2D &>(tex);;
+ t2d.image(0, t2d.ifmt, GL_UNSIGNED_BYTE, data.data());
+}
+
+void Texture2D::Loader::storage(PixelFormat fmt, unsigned w, unsigned h, unsigned b)
+{
+ static_cast<Texture2D &>(tex).storage(fmt, w, h, b);
+}
+
} // namespace GL
} // namespace Msp
Loader(Texture2D &);
private:
void image_data(const std::string &);
+ void raw_data(const std::string &);
+ void storage(PixelFormat, unsigned, unsigned, unsigned);
};
private:
TexUnit::TexUnit():
texture(0)
{
- require_version(1, 3);
}
bool TexUnit::set_texture(const Texture *tex)
if(units.size()<=n)
units.resize(n+1);
- glActiveTexture(GL_TEXTURE0+n);
+ if(cur_unit!=&units[n] && (cur_unit || n))
+ {
+ require_version(1, 3);
+ glActiveTexture(GL_TEXTURE0+n);
+ }
cur_unit=&units[n];
return units[n];
#ifndef MSP_GL_TYPES_H_
#define MSP_GL_TYPES_H_
+#include <GL/gl.h>
+
namespace Msp {
namespace GL {
+enum DataType
+{
+ BYTE = GL_BYTE,
+ UNSIGNED_BYTE = GL_UNSIGNED_BYTE,
+ SHORT = GL_SHORT,
+ UNSIGNED_SHORT = GL_UNSIGNED_SHORT,
+ INT = GL_INT,
+ UNSIGNED_INT = GL_UNSIGNED_INT,
+ FLOAT = GL_FLOAT,
+ DOUBLE = GL_DOUBLE
+};
+
typedef signed char byte;
typedef unsigned char ubyte;
typedef unsigned sizei;
update_data();
}
+void VertexArray::reserve(unsigned n)
+{
+ data.reserve(n*stride);
+}
+
void VertexArray::clear()
{
data.clear();
const float *base=vbuf?0:&data[0];
uint offset=0;
uint found=0;
+ uint bpv=stride*sizeof(float);
for(uint fmt=format; fmt; fmt>>=4)
{
- uint size=(fmt&3)+1;
+ uint sz=(fmt&3)+1;
switch(fmt&12)
{
case 0:
- glVertexPointer(size, GL_FLOAT, stride, base+offset);
+ glVertexPointer(sz, GL_FLOAT, bpv, base+offset);
break;
case 4:
- glNormalPointer(GL_FLOAT, stride, base+offset);
+ glNormalPointer(GL_FLOAT, bpv, base+offset);
break;
case 8:
- glTexCoordPointer(size, GL_FLOAT, stride, base+offset);
+ glTexCoordPointer(sz, GL_FLOAT, bpv, base+offset);
break;
case 12:
- if(size==1)
- glColorPointer(4, GL_UNSIGNED_BYTE, stride, base+offset);
+ if(sz==1)
+ glColorPointer(4, GL_UNSIGNED_BYTE, bpv, base+offset);
else
- glColorPointer(size, GL_FLOAT, stride, base+offset);
+ glColorPointer(sz, GL_FLOAT, bpv, base+offset);
break;
}
found|=1<<((fmt&12)>>2);
- offset+=size;
+ offset+=sz;
}
set_array(GL_VERTEX_ARRAY, found&1, 1);
#include <vector>
#include <msp/core/refptr.h>
#include <msp/datafile/loader.h>
+#include "primitivetype.h"
#include "types.h"
#include "vertexarraybuilder.h"
#include "vertexformat.h"
const std::vector<float> &get_data() const { return data; }
void use_vertex_buffer();
void use_vertex_buffer(VertexBuffer *);
+ void reserve(unsigned);
+ unsigned size() const { return data.size()/stride; }
void clear();
void reset(VertexFormat);
RefPtr<VertexArrayBuilder> modify();
uint stride=0;
for(uint fmt=f; fmt; fmt>>=4)
stride+=(fmt&3)+1;
- return stride*sizeof(float);
+ return stride;
}
std::istream &operator>>(std::istream &in, VertexFormat &f)