From d1800d7ea80290f4913d0203241cef1409656522 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 4 Feb 2008 12:21:42 +0000 Subject: [PATCH] Make the use of DevIL optional Allow speifying storage and raw data in texture files Add class PrimitiveBuilder Change Font to build all vertices of a string and then draw them at once Only require OpenGL 1.3 in TexUnit when actually changing the unit Add a python script to create .tex files with raw data from images --- Build | 11 +++-- maketex.py | 36 ++++++++++++++++ source/font.cpp | 83 ++++++++++++------------------------- source/font.h | 8 +--- source/ilwrap.cpp | 32 ++++++++++++++ source/immediate.cpp | 33 ++------------- source/immediate.h | 20 ++++----- source/pixelformat.cpp | 53 +++++++++++++++++++++++ source/pixelformat.h | 3 ++ source/primitivebuilder.cpp | 60 +++++++++++++++++++++++++++ source/primitivebuilder.h | 48 +++++++++++++++++++++ source/texture2d.cpp | 13 ++++++ source/texture2d.h | 2 + source/texunit.cpp | 7 +++- source/types.h | 14 +++++++ source/vertexarray.cpp | 22 ++++++---- source/vertexarray.h | 3 ++ source/vertexformat.cpp | 2 +- 18 files changed, 331 insertions(+), 119 deletions(-) create mode 100755 maketex.py create mode 100644 source/pixelformat.cpp create mode 100644 source/primitivebuilder.cpp create mode 100644 source/primitivebuilder.h diff --git a/Build b/Build index 37e2ef7d..cc0de245 100644 --- a/Build +++ b/Build @@ -5,6 +5,8 @@ package "mspgl" 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" { @@ -18,10 +20,13 @@ package "mspgl" }; }; require "mspdatafile"; - require "devil"; - build_info + if "with_devil" { - library "ILU"; + require "devil"; + build_info + { + library "ILU"; + }; }; library "mspgl" diff --git a/maketex.py b/maketex.py new file mode 100755 index 00000000..17012c8a --- /dev/null +++ b/maketex.py @@ -0,0 +1,36 @@ +#!/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") diff --git a/source/font.cpp b/source/font.cpp index 637569f2..7d9b306b 100644 --- a/source/font.cpp +++ b/source/font.cpp @@ -7,6 +7,7 @@ Distributed under the LGPL #include "gl.h" #include "font.h" +#include "primitivetype.h" #include "texture2d.h" using namespace std; @@ -18,8 +19,7 @@ Font::Font(): tex(0), default_size(1), ascent(1), - descent(0), - varray((TEXCOORD2, VERTEX2)) + descent(0) { } void Font::set_texture(const Texture2D &t) @@ -40,11 +40,7 @@ void Font::add_glyph(unsigned code, float x1, float y1, float x2, float y2, floa glyph.off_x=ox; glyph.off_y=oy; glyph.advance=adv; - glyph.index=glyphs.size(); glyphs.insert(GlyphMap::value_type(code, glyph)); - - RefPtr va_builder=varray.modify(); - create_glyph_vertices(glyph, *va_builder); } float Font::get_string_width(const string &str, Codecs::Decoder &dec) const @@ -59,58 +55,38 @@ 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 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 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 @@ -144,11 +120,6 @@ DataFile::Collection &Font::Loader::get_collection() return *coll; } -Font::Loader::~Loader() -{ - font.create_glyph_vertices(); -} - void Font::Loader::init() { add("default_size", &Font::default_size); diff --git a/source/font.h b/source/font.h index 68c035a6..f647dbbd 100644 --- a/source/font.h +++ b/source/font.h @@ -33,7 +33,6 @@ public: Loader(Font &); Loader(Font &, DataFile::Collection &); - ~Loader(); Font &get_object() { return font; } DataFile::Collection &get_collection(); private: @@ -94,7 +93,6 @@ private: float w,h; float off_x, off_y; float advance; - unsigned index; }; typedef std::map GlyphMap; @@ -103,12 +101,8 @@ private: 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; }; diff --git a/source/ilwrap.cpp b/source/ilwrap.cpp index a1ae1631..b9fb4998 100644 --- a/source/ilwrap.cpp +++ b/source/ilwrap.cpp @@ -5,7 +5,9 @@ Copyright © 2007 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ +#ifdef WITH_DEVIL #include +#endif #include #include "ilwrap.h" @@ -16,6 +18,7 @@ namespace GL { Image::Image() { +#ifdef WITH_DEVIL static bool init_done=false; if(!init_done) @@ -27,29 +30,43 @@ Image::Image() } 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(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(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; @@ -61,21 +78,36 @@ PixelFormat Image::get_format() const 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 diff --git a/source/immediate.cpp b/source/immediate.cpp index f3413974..8e761f43 100644 --- a/source/immediate.cpp +++ b/source/immediate.cpp @@ -11,41 +11,16 @@ namespace Msp { 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 diff --git a/source/immediate.h b/source/immediate.h index b979973c..7e99272b 100644 --- a/source/immediate.h +++ b/source/immediate.h @@ -8,9 +8,7 @@ Distributed under the LGPL #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 { @@ -22,20 +20,16 @@ end() to terminate the batch. However, unlike OpenGL immediate mode, vertices 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 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 diff --git a/source/pixelformat.cpp b/source/pixelformat.cpp new file mode 100644 index 00000000..738b796c --- /dev/null +++ b/source/pixelformat.cpp @@ -0,0 +1,53 @@ +/* $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 diff --git a/source/pixelformat.h b/source/pixelformat.h index 6579700d..6980ec8a 100644 --- a/source/pixelformat.h +++ b/source/pixelformat.h @@ -8,6 +8,7 @@ Distributed under the LGPL #ifndef MSP_GL_PIXELFORMAT_H_ #define MSP_GL_PIXELFORMAT_H_ +#include #include "gl.h" namespace Msp { @@ -30,6 +31,8 @@ enum PixelFormat LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA }; +std::istream &operator>>(std::istream &, PixelFormat &); + } // namespace GL } // namespace Msp diff --git a/source/primitivebuilder.cpp b/source/primitivebuilder.cpp new file mode 100644 index 00000000..ca8f4f3c --- /dev/null +++ b/source/primitivebuilder.cpp @@ -0,0 +1,60 @@ +/* $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 diff --git a/source/primitivebuilder.h b/source/primitivebuilder.h new file mode 100644 index 00000000..cfe0a02c --- /dev/null +++ b/source/primitivebuilder.h @@ -0,0 +1,48 @@ +/* $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 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 diff --git a/source/texture2d.cpp b/source/texture2d.cpp index fbf86a43..8a93d031 100644 --- a/source/texture2d.cpp +++ b/source/texture2d.cpp @@ -81,6 +81,8 @@ Texture2D::Loader::Loader(Texture2D &t): 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) @@ -91,5 +93,16 @@ void Texture2D::Loader::image_data(const string &data) static_cast(tex).image(img); } +void Texture2D::Loader::raw_data(const string &data) +{ + Texture2D &t2d=static_cast(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(tex).storage(fmt, w, h, b); +} + } // namespace GL } // namespace Msp diff --git a/source/texture2d.h b/source/texture2d.h index b62466cb..30eab26c 100644 --- a/source/texture2d.h +++ b/source/texture2d.h @@ -30,6 +30,8 @@ public: Loader(Texture2D &); private: void image_data(const std::string &); + void raw_data(const std::string &); + void storage(PixelFormat, unsigned, unsigned, unsigned); }; private: diff --git a/source/texunit.cpp b/source/texunit.cpp index bda75991..ba3e7ca6 100644 --- a/source/texunit.cpp +++ b/source/texunit.cpp @@ -18,7 +18,6 @@ namespace GL { TexUnit::TexUnit(): texture(0) { - require_version(1, 3); } bool TexUnit::set_texture(const Texture *tex) @@ -33,7 +32,11 @@ TexUnit &TexUnit::activate(unsigned n) 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]; diff --git a/source/types.h b/source/types.h index 4fd2d4b0..0ae9e77e 100644 --- a/source/types.h +++ b/source/types.h @@ -8,9 +8,23 @@ Distributed under the LGPL #ifndef MSP_GL_TYPES_H_ #define MSP_GL_TYPES_H_ +#include + 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; diff --git a/source/vertexarray.cpp b/source/vertexarray.cpp index 6da0f9c0..38d490c0 100644 --- a/source/vertexarray.cpp +++ b/source/vertexarray.cpp @@ -48,6 +48,11 @@ void VertexArray::use_vertex_buffer(VertexBuffer *b) update_data(); } +void VertexArray::reserve(unsigned n) +{ + data.reserve(n*stride); +} + void VertexArray::clear() { data.clear(); @@ -78,29 +83,30 @@ void VertexArray::apply() const 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); diff --git a/source/vertexarray.h b/source/vertexarray.h index 9610905d..b1b5fdee 100644 --- a/source/vertexarray.h +++ b/source/vertexarray.h @@ -11,6 +11,7 @@ Distributed under the LGPL #include #include #include +#include "primitivetype.h" #include "types.h" #include "vertexarraybuilder.h" #include "vertexformat.h" @@ -36,6 +37,8 @@ public: const std::vector &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 modify(); diff --git a/source/vertexformat.cpp b/source/vertexformat.cpp index 5c02f2ab..bf2d9095 100644 --- a/source/vertexformat.cpp +++ b/source/vertexformat.cpp @@ -15,7 +15,7 @@ uint get_stride(VertexFormat f) 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) -- 2.45.2