--- /dev/null
+package "mspgl"
+{
+ description "C++ wrappers for OpenGL";
+ version "0.1";
+
+ require "opengl";
+ require "mspparser";
+ require "libpng";
+
+ library "mspgl"
+ {
+ source "source";
+ install true;
+ install_headers "msp/gl";
+ };
+};
--- /dev/null
+#include <GL/gl.h>
+#include "font.h"
+#include "texture2d.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Font::Font():
+ tex(0),
+ own_tex(false)
+{ }
+
+void Font::set_texture(const Texture2D &t)
+{
+ tex=&t;
+}
+
+void Font::add_glyph(wchar_t code, float x1, float y1, float x2, float y2, float w, float h, float desc, float adv)
+{
+ Glyph glyph;
+ glyph.code=code;
+ glyph.x1=x1;
+ glyph.y1=y1;
+ glyph.x2=x2;
+ glyph.y2=y2;
+ glyph.w=w;
+ glyph.h=h;
+ glyph.descent=desc;
+ glyph.advance=adv;
+}
+
+float Font::get_string_width(const string &str) const
+{
+ float x=0;
+
+ for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
+ {
+ GlyphMap::const_iterator j=glyphs.find((unsigned char)*i);
+ if(j==glyphs.end())
+ continue;
+
+ const Glyph &glyph=j->second;
+
+ x+=glyph.advance;
+ }
+
+ return x;
+}
+
+void Font::draw_string(const string &str) const
+{
+ float x=0;
+ float data[16];
+
+ prepare(data);
+
+ for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
+ draw_glyph((unsigned char)*i, data, x);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+Font::~Font()
+{
+ if(own_tex)
+ delete tex;
+}
+
+void Font::prepare(float *data) const
+{
+ tex->bind();
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 4*sizeof(float), data);
+ glVertexPointer(2, GL_FLOAT, 4*sizeof(float), data+2);
+}
+
+void Font::draw_glyph(wchar_t code, float *data, float &x) const
+{
+ GlyphMap::const_iterator i=glyphs.find(code);
+ if(i==glyphs.end())
+ return;
+
+ const Glyph &glyph=i->second;
+
+ data[0]=data[12]=glyph.x1;
+ data[1]=data[5]=glyph.y1;
+ data[4]=data[8]=glyph.x2;
+ data[9]=data[13]=glyph.y2;
+
+ data[2]=data[14]=x;
+ data[3]=data[7]=glyph.descent;
+ data[6]=data[10]=x+glyph.w;
+ data[11]=data[15]=glyph.h+glyph.descent;
+
+ glDrawArrays(GL_QUADS, 0, 4);
+
+ x+=glyph.advance;
+}
+
+Font::Loader::Loader(Font &f):
+ font(f)
+{
+ add("texture", &Loader::texture);
+ add("glyph", &Loader::glyph);
+}
+
+void Font::Loader::texture(const string &t)
+{
+ Texture2D *tex=new Texture2D;
+ tex->parameter(GL_GENERATE_MIPMAP, 1);
+ font.tex=tex;
+ tex->image(t);
+ font.own_tex=true;
+}
+
+void Font::Loader::glyph(unsigned c)
+{
+ Glyph gl;
+ gl.code=c;
+ load_sub(gl);
+ font.glyphs.insert(GlyphMap::value_type(c, gl));
+}
+
+Font::Glyph::Loader::Loader(Glyph &g):
+ glyph(g)
+{
+ add("texcoords", &Loader::texcoords);
+ add("size", &Loader::size);
+ add("descent", &Glyph::descent);
+ add("advance", &Glyph::advance);
+}
+
+void Font::Glyph::Loader::texcoords(float x1, float y1, float x2, float y2)
+{
+ glyph.x1=x1;
+ glyph.y1=y1;
+ glyph.x2=x2;
+ glyph.y2=y2;
+}
+
+void Font::Glyph::Loader::size(float w, float h)
+{
+ glyph.w=w;
+ glyph.h=h;
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef FONT_H_
+#define FONT_H_
+
+#include <map>
+#include <string>
+#include <msp/parser/loader.h>
+
+namespace Msp {
+namespace GL {
+
+class Texture2D;
+
+class Font
+{
+public:
+ class Loader: public Msp::Parser::Loader
+ {
+ public:
+ Loader(Font &);
+ private:
+ Font &font;
+
+ void texture(const std::string &);
+ void glyph(unsigned);
+ };
+
+ Font();
+ void set_texture(const Texture2D &);
+ void add_glyph(wchar_t, float, float, float, float, float, float, float, float);
+ float get_string_width(const std::string &) const;
+ void draw_glyph(wchar_t);
+ void draw_string(const std::string &) const;
+ void draw_multiline(const std::string &) const;
+ ~Font();
+private:
+ struct Glyph
+ {
+ class Loader: public Msp::Parser::Loader
+ {
+ public:
+ Loader(Glyph &);
+ Glyph &get_object() { return glyph; }
+ private:
+ Glyph &glyph;
+
+ void texcoords(float, float, float, float);
+ void size(float, float);
+ };
+
+ wchar_t code;
+ float x1,y1;
+ float x2,y2;
+ float w,h;
+ float descent;
+ float advance;
+ };
+ typedef std::map<wchar_t, Glyph> GlyphMap;
+
+ const Texture2D *tex;
+ bool own_tex;
+ GlyphMap glyphs;
+
+ void prepare(float *) const;
+ void draw_glyph(wchar_t, float *, float &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include "misc.h"
+
+namespace Msp {
+namespace GL {
+
+void set(GLenum state, bool value)
+{
+ if(value)
+ glEnable(state);
+ else
+ glDisable(state);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_MISC_H_
+#define MSP_GL_MISC_H_
+
+#include <GL/gl.h>
+
+namespace Msp {
+namespace GL {
+
+void set(GLenum, bool);
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include "rendermode.h"
+#include "select.h"
+
+namespace Msp {
+namespace GL {
+
+int render_mode(RenderMode rm)
+{
+ int old_rm;
+ glGetIntegerv(GL_RENDER_MODE, &old_rm);
+
+ int result=glRenderMode(rm);
+
+ if(old_rm==SELECT)
+ _parse_internal_select_records(result);
+
+ return result;
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_RENDERMODE_H_
+#define MSP_GL_RENDERMODE_H_
+
+#include <GL/gl.h>
+
+namespace Msp {
+namespace GL {
+
+enum RenderMode
+{
+ RENDER = GL_RENDER,
+ SELECT = GL_SELECT,
+ FEEDBACK = GL_FEEDBACK
+};
+
+int render_mode(RenderMode);
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <GL/gl.h>
+#include "select.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+vector<SelectRecord> *select_buf=0;
+vector<uint> select_buf_int;
+
+void select_buffer(vector<SelectRecord> &buf)
+{
+ select_buf_int.resize(1024);
+ glSelectBuffer(select_buf_int.size(), &select_buf_int[0]);
+ select_buf=&buf;
+}
+
+void parse_select_records(const uint *buf, uint count, vector<SelectRecord> &tbuf)
+{
+ uint i=0;
+ while(count--)
+ {
+ SelectRecord record;
+
+ uint n_names=buf[i++];
+ record.min_depth=buf[i++];
+ record.max_depth=buf[i++];
+
+ record.names.reserve(n_names);
+ while(n_names--)
+ record.names.push_back(buf[i++]);
+
+ tbuf.push_back(record);
+ }
+}
+
+void _parse_internal_select_records(uint count)
+{
+ if(!select_buf)
+ //XXX throw InvalidOperation();
+ return;
+ parse_select_records(&select_buf_int[0], count, *select_buf);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_SELECT_H_
+#define MSP_GL_SELECT_H_
+
+#include <vector>
+
+namespace Msp {
+namespace GL {
+
+struct SelectRecord
+{
+ uint min_depth;
+ uint max_depth;
+ std::vector<uint> names;
+};
+
+void select_buffer(std::vector<SelectRecord> &);
+void parse_select_records(const uint *buf, uint, std::vector<SelectRecord> &);
+
+void _parse_internal_select_records(uint);
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_GL_TEXENV_H_
+#define MSP_GL_TEXENV_H_
+
+namespace Msp {
+namespace GL {
+
+class TexEnv
+{
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include "texture.h"
+
+namespace Msp {
+namespace GL {
+
+void Texture::bind() const
+{
+ if(!target) return;
+
+ glEnable(target);
+ glBindTexture(target, id);
+ bound=this;
+}
+
+void Texture::parameter(GLenum param, int value)
+{
+ if(bound!=this) bind();
+
+ glTexParameteri(target, param, value);
+}
+
+void Texture::parameter(GLenum param, float value)
+{
+ if(bound!=this) bind();
+
+ glTexParameterf(target, param, value);
+}
+
+sizei Texture::get_width(int level) const
+{
+ if(bound!=this) bind();
+
+ int width;
+ glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
+ return width;
+}
+
+sizei Texture::get_height(int level) const
+{
+ if(bound!=this) bind();
+
+ int height;
+ glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
+ return height;
+}
+
+sizei Texture::get_depth(int level) const
+{
+ if(bound!=this) bind();
+
+ int depth;
+ glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &depth);
+ return depth;
+}
+
+Texture::~Texture()
+{
+ glDeleteTextures(1, &id);
+}
+
+Texture::Texture():
+ target(0)
+{
+ glGenTextures(1, &id);
+}
+
+const Texture *Texture::bound=0;
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_TEXTURE_H_
+#define MSP_GL_TEXTURE_H_
+
+#include <GL/gl.h>
+#include "types.h"
+
+namespace Msp {
+namespace GL {
+
+enum TextureFilter
+{
+ NEAREST = GL_NEAREST,
+ LINEAR = GL_LINEAR,
+ NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST,
+ NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR,
+ LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST,
+ LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR
+};
+
+enum TextureFormat
+{
+ LUMINANCE8,
+ LUMINANCE8_ALPHA8,
+ RGB8,
+ RGBA8,
+ BGR8,
+ BGRA8
+};
+
+class Texture
+{
+public:
+ void bind() const;
+ void parameter(GLenum, int);
+ void parameter(GLenum, float);
+ void set_min_filter(TextureFilter f) { parameter(GL_TEXTURE_MIN_FILTER, f); }
+ void set_mag_filter(TextureFilter f) { parameter(GL_TEXTURE_MAG_FILTER, f); }
+ uint get_id() const { return id; }
+ sizei get_width(int =0) const;
+ sizei get_height(int =0) const;
+ sizei get_depth(int =0) const;
+ ~Texture();
+protected:
+ uint id;
+ GLenum target;
+
+ Texture();
+
+ static const Texture *bound;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <png.h>
+#include <msp/error.h>
+#include "texture2d.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Texture2D::Texture2D()
+{
+ target=GL_TEXTURE_2D;
+}
+
+/**
+Uploads an image into the texture. Direct wrapper for glTexImage2D.
+*/
+void Texture2D::image(int level, int ifmt, sizei width, sizei height, int border, GLenum fmt, GLenum type, void *data)
+{
+ if(bound!=this) bind();
+ glTexImage2D(target, level, ifmt, width, height, border, fmt, type, data);
+}
+
+/**
+Uploads an image into the texture.
+*/
+void Texture2D::image(int level, sizei width, sizei height, TextureFormat tfmt, void *data)
+{
+ int ifmt;
+ int fmt;
+ int type;
+
+ switch(tfmt)
+ {
+ case LUMINANCE8: ifmt=GL_LUMINANCE; fmt=GL_LUMINANCE; type=GL_UNSIGNED_BYTE; break;
+ case LUMINANCE8_ALPHA8: ifmt=GL_LUMINANCE_ALPHA; fmt=GL_LUMINANCE_ALPHA; type=GL_UNSIGNED_BYTE; break;
+ case RGB8: ifmt=GL_RGB; fmt=GL_RGB; type=GL_UNSIGNED_BYTE; break;
+ case RGBA8: ifmt=GL_RGBA; fmt=GL_RGBA; type=GL_UNSIGNED_INT_8_8_8_8; break;
+ case BGR8: ifmt=GL_RGB; fmt=GL_BGR; type=GL_UNSIGNED_BYTE; break;
+ case BGRA8: ifmt=GL_RGBA; fmt=GL_BGRA; type=GL_UNSIGNED_INT_8_8_8_8; break;
+ default: return;
+ }
+
+ image(level, ifmt, width, height, 0, fmt, type, data);
+}
+
+/**
+Loads an image from a file and uploads it into the texture. Currently assumes
+the file to be a PNG image.
+*/
+void Texture2D::image(const string &fn)
+{
+ FILE *file=fopen(fn.c_str(), "r");
+ if(!file) throw Exception("Couldn't open "+fn);
+
+ char sig[8];
+ fread(sig, 8, 1, file);
+ if(png_sig_cmp((png_byte *)sig, 0, 8))
+ throw Exception("Not a PNG image");
+
+ png_struct *pngs=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ png_info *pngi=png_create_info_struct(pngs);
+
+ if(setjmp(png_jmpbuf(pngs)))
+ {
+ png_destroy_read_struct(&pngs, &pngi, 0);
+ fclose(file);
+ throw Exception("PNG error");
+ }
+ png_init_io(pngs, file);
+ png_set_sig_bytes(pngs, 8);
+
+ png_read_info(pngs, pngi);
+
+ unsigned width=png_get_image_width(pngs, pngi);
+ unsigned height=png_get_image_height(pngs, pngi);
+ unsigned depth=png_get_bit_depth(pngs, pngi);
+ unsigned ctype=png_get_color_type(pngs, pngi);
+
+ if(ctype==PNG_COLOR_TYPE_PALETTE || depth<8)
+ {
+ png_destroy_read_struct(&pngs, &pngi, 0);
+ fclose(file);
+ throw Exception("Invalid color type or bit depth");
+ }
+
+ if(depth==16)
+ png_set_strip_16(pngs);
+
+ TextureFormat fmt;
+ unsigned planes;
+
+ switch(ctype)
+ {
+ case PNG_COLOR_TYPE_GRAY: fmt=LUMINANCE8; planes=1; break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA: fmt=LUMINANCE8_ALPHA8; planes=2; break;
+ case PNG_COLOR_TYPE_RGB: fmt=RGB8; planes=3; break;
+ case PNG_COLOR_TYPE_RGB_ALPHA: fmt=RGBA8; planes=4; break;
+ }
+
+ png_byte *data=(png_byte *)malloc(width*height*planes);
+ png_byte *row_ptrs[height];
+ for(unsigned i=0; i<height; ++i)
+ row_ptrs[i]=data+(height-1-i)*width*planes;
+
+ png_read_image(pngs, row_ptrs);
+
+ image(0, width, height, fmt, data);
+ free(data);
+
+ png_destroy_read_struct(&pngs, &pngi, 0);
+ fclose(file);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_TEXTURE2D_H_
+#define MSP_GL_TEXTURE2D_H_
+
+#include <string>
+#include "texture.h"
+
+namespace Msp {
+namespace GL {
+
+class Texture2D: public Texture
+{
+public:
+ Texture2D();
+ void image(int, int, sizei, sizei, int, GLenum, GLenum, void *);
+ void image(int, sizei, sizei, TextureFormat, void *);
+ void image(const std::string &);
+private:
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#ifndef MSP_GL_TYPES_H_
+#define MSP_GL_TYPES_H_
+
+namespace Msp {
+namespace GL {
+
+typedef signed char byte;
+typedef unsigned char ubyte;
+typedef unsigned sizei;
+typedef unsigned uint;
+
+} // namespace GL
+} // namespace Msp
+
+#endif