diff --git a/modules/gfx/pymod/CMakeLists.txt b/modules/gfx/pymod/CMakeLists.txt index 0ee14167c4f19232a7e4ecbdda746ab6c1b6a2a9..cdc4abb2158de61e9639cc50d839fc760c28e30d 100644 --- a/modules/gfx/pymod/CMakeLists.txt +++ b/modules/gfx/pymod/CMakeLists.txt @@ -15,6 +15,7 @@ set(OST_GFX_PYMOD_SOURCES export_color_ops.cc export_glwin_base.cc export_exporter.cc + export_bitmap.cc ) if (ENABLE_IMG) @@ -29,4 +30,4 @@ set(GRADIENT_FILE copy_if_different("${CMAKE_CURRENT_SOURCE_DIR}" "${STAGE_DIR}/share/openstructure/scene" "${GRADIENT_FILE}" "PRESET GRADIENTS" _ost_gfx) -install(FILES ${GRADIENT_FILE} DESTINATION "share/openstructure/scene") \ No newline at end of file +install(FILES ${GRADIENT_FILE} DESTINATION "share/openstructure/scene") diff --git a/modules/gfx/pymod/export_bitmap.cc b/modules/gfx/pymod/export_bitmap.cc new file mode 100644 index 0000000000000000000000000000000000000000..d8e944d21462cfaa90d72b7c99920882c6887722 --- /dev/null +++ b/modules/gfx/pymod/export_bitmap.cc @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#include <boost/python.hpp> +using namespace boost::python; + +#include <ost/gfx/bitmap_io.hh> +using namespace ost; +using namespace ost::gfx; + +namespace { + unsigned int get_width(const Bitmap& bm) {return bm.width;} + void set_width(Bitmap& bm, unsigned int w) {bm.width=w;} + unsigned int get_height(const Bitmap& bm) {return bm.height;} + void set_height(Bitmap& bm, unsigned int w) {bm.height=w;} + + Bitmap import1(const std::string& n) {return ImportBitmap(n);} + Bitmap import2(const std::string& n, std::string e) {return ImportBitmap(n,e);} +} + +void export_bitmap() +{ + class_<Bitmap>("Bitmap",init<>()) + .add_property("width",get_width,set_width) + .add_property("height",get_height,set_height) + ; + + def("ExportBitmap",ExportBitmap); + def("ImportBitmap",import1); + def("ImportBitmap",import2); +} diff --git a/modules/gfx/pymod/export_scene.cc b/modules/gfx/pymod/export_scene.cc index 39d1fde6bde504a407dea60247b7cadf01fb5b8a..23ff9d687b497960588b169884690ff6a071243e 100644 --- a/modules/gfx/pymod/export_scene.cc +++ b/modules/gfx/pymod/export_scene.cc @@ -65,6 +65,10 @@ geom::AlignedCuboid scene_get_bb3(Scene* scene, const geom::Transform& tf) return scene->GetBoundingBox(tf); } +void (Scene::*scene_set_bg1)(const Color&) = &Scene::SetBackground; +void (Scene::*scene_set_bg2)(const Gradient&) = &Scene::SetBackground; +void (Scene::*scene_set_bg3)(const Bitmap&) = &Scene::SetBackground; + } // anon ns @@ -124,10 +128,12 @@ void export_Scene() .def("Resize", &Scene::Resize) .def("HasNode", &Scene::HasNode) .def("GetBackground", &Scene::GetBackground) - .def("SetBackground", &Scene::SetBackground) + .def("SetBackground", scene_set_bg1) + .def("SetBackground", scene_set_bg2) + .def("SetBackground", scene_set_bg3) .add_property("bg", &Scene::GetBackground, - &Scene::SetBackground) + scene_set_bg1) .def("GetProjection",&Scene::GetProjection) .add_property("projection",&Scene::GetProjection) .def("GetInvertedProjection",&Scene::GetInvertedProjection) diff --git a/modules/gfx/pymod/wrap_gfx.cc b/modules/gfx/pymod/wrap_gfx.cc index 28229edf12ada259a25443f363d43db51199291d..b28c496597e9ae55489a1a0930fdfe2b00fcc620 100644 --- a/modules/gfx/pymod/wrap_gfx.cc +++ b/modules/gfx/pymod/wrap_gfx.cc @@ -37,6 +37,7 @@ extern void export_primlist(); extern void export_primitives(); extern void export_color(); extern void export_gradient(); +extern void export_bitmap(); extern void export_Exporter(); #if OST_IMG_ENABLED @@ -73,6 +74,7 @@ BOOST_PYTHON_MODULE(_ost_gfx) export_primlist(); export_color(); export_gradient(); + export_bitmap(); enum_<RenderMode::Type>("RenderMode") .value("SIMPLE",RenderMode::SIMPLE) diff --git a/modules/gfx/src/bitmap_io.cc b/modules/gfx/src/bitmap_io.cc index 6d36daaa1c339f8c4e995e90dc07f81c0cb10bf7..ab42f9de5a67242ee9edf51a705c6cec4a078121 100644 --- a/modules/gfx/src/bitmap_io.cc +++ b/modules/gfx/src/bitmap_io.cc @@ -21,15 +21,19 @@ */ #include <vector> +#include <sstream> #define ZLIB_WINAPI #include <png.h> #include <ost/log.hh> +#include <ost/message.hh> #include "bitmap_io.hh" namespace ost { namespace gfx { +namespace { + void export_png(const String& filename, unsigned int width, unsigned int height, unsigned char* data) { FILE *fp; @@ -181,15 +185,38 @@ Bitmap import_png(const String& filename) return bm; } -void BitmapExport(const String& fname, const String& ext, unsigned int width, unsigned int height,unsigned char* data) +std::string get_ext(const std::string& fname) { - if(ext==".png") export_png(fname,width,height,data); + int d_index=fname.rfind('.'); + if (d_index==-1) { + return ""; + } + return fname.substr(d_index+1); +} + +} + +void ExportBitmap(const String& fname, std::string ext, unsigned int width, unsigned int height,unsigned char* data) +{ + if(ext.empty()) ext=get_ext(fname); + if(ext=="png") { + export_png(fname,width,height,data); + } else { + std::ostringstream msg; + msg << "unsupported bitmap format [" << ext << "]"; + throw Error(msg.str()); + } } -Bitmap BitmapImport(const String& fname, const String& ext) +Bitmap ImportBitmap(const String& fname, std::string ext) { - if(ext==".png") { + if(ext.empty()) ext=get_ext(fname); + if(ext=="png") { return import_png(fname); + } else { + std::ostringstream msg; + msg << "unsupported bitmap format [" << ext << "]"; + throw Error(msg.str()); } return Bitmap(); } diff --git a/modules/gfx/src/bitmap_io.hh b/modules/gfx/src/bitmap_io.hh index afddc220bc6f91f3d60507b1d8fe1d47341292cf..e8263d97f75aa47a1f3ad76dfdd9df10941477c2 100644 --- a/modules/gfx/src/bitmap_io.hh +++ b/modules/gfx/src/bitmap_io.hh @@ -32,6 +32,7 @@ namespace ost { namespace gfx { // very rudimentary bitmap support +// TODO: gl tex mapping association struct Bitmap { /* @@ -46,9 +47,9 @@ struct Bitmap boost::shared_array<unsigned char> data; }; -void BitmapExport(const String& fname, const String& ext, unsigned int width, unsigned int height,unsigned char* data); +void ExportBitmap(const String& fname, std::string ext, unsigned int width, unsigned int height,unsigned char* data); -Bitmap BitmapImport(const String& fname, const String& ext); +Bitmap ImportBitmap(const String& fname, std::string ext=""); }} // ns diff --git a/modules/gfx/src/gfx_test_object.cc b/modules/gfx/src/gfx_test_object.cc index 5b238473055efe537db846838267fc842a85844f..7e60ab6d8657d35b44d2eb0840a0c0f7640ad76a 100644 --- a/modules/gfx/src/gfx_test_object.cc +++ b/modules/gfx/src/gfx_test_object.cc @@ -61,7 +61,7 @@ GfxTestObj::GfxTestObj(): bf::path ost_root_dir(ost_root); bf::path tex_file(ost_root_dir / "textures/test_texture.png"); - Texture tex(BitmapImport(tex_file.string(),".png")); + Texture tex(ImportBitmap(tex_file.string())); if(!tex.IsValid()) { LOG_ERROR("error loading " << tex_file.string()); } else { diff --git a/modules/gfx/src/gl_helper.hh b/modules/gfx/src/gl_helper.hh index dac567894edea06c8c6156dae1497dcd52c65f81..77346056346c4ec937b90dba4bebaedd9fe5fb59 100644 --- a/modules/gfx/src/gl_helper.hh +++ b/modules/gfx/src/gl_helper.hh @@ -39,12 +39,16 @@ Author: Juergen Haas #include <ost/log.hh> -inline void check_gl_error() +inline void check_gl_error(const std::string& m="") { + #ifndef NDEBUG GLenum error_code; if((error_code=glGetError())!=GL_NO_ERROR) { - LOG_VERBOSE("GL error: " << gluErrorString(error_code)); + if(!m.empty()) { + LOG_VERBOSE("GL error in [" << m << "]: " << gluErrorString(error_code)); + } } + #endif } inline void glVertex3v(double* v){ diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc index 2650eea5b09f5169bee74a9e984437573619aa3c..9212d8eab37f015b5019c25438efe75d162fb268 100644 --- a/modules/gfx/src/scene.cc +++ b/modules/gfx/src/scene.cc @@ -135,7 +135,12 @@ Scene::Scene(): stereo_iod_(4.0), stereo_distance_(0.0), scene_left_tex_(), - scene_right_tex_() + scene_right_tex_(), + bg_mode_(0), + update_bg_(false), + bg_grad_(), + bg_bm_(), + bg_tex_() { transform_.SetTrans(Vec3(0,0,-100)); } @@ -394,6 +399,8 @@ void Scene::InitGL(bool full) { LOG_VERBOSE("Scene: initializing GL state"); + check_gl_error(); // clear error flag + if(full) { LOG_INFO(glGetString(GL_RENDERER) << ", openGL version " << glGetString(GL_VERSION)); @@ -506,8 +513,10 @@ void Scene::InitGL(bool full) } if(full) { + LOG_DEBUG("Scene: initalizing textures"); glGenTextures(1,&scene_left_tex_); glGenTextures(1,&scene_right_tex_); + glGenTextures(1,&bg_tex_); } glEnable(GL_TEXTURE_2D); @@ -531,6 +540,14 @@ void Scene::InitGL(bool full) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(GL_TEXTURE_2D, bg_tex_); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); + LOG_DEBUG("Scene: calling gl init for all objects"); GfxObjInitGL initgl; this->Apply(initgl); @@ -539,6 +556,8 @@ void Scene::InitGL(bool full) gl_init_=true; if(!def_shading_mode_.empty()) SetShadingMode(def_shading_mode_); + + check_gl_error("InitGL()"); } void Scene::RequestRedraw() @@ -556,6 +575,7 @@ void Scene::StatusMessage(const String& s) void Scene::SetBackground(const Color& c) { background_=c; + bg_mode_=0; if(gl_init_) { glClearColor(c.Red(),c.Green(),c.Blue(),c.Alpha()); SetFogColor(c); @@ -563,6 +583,65 @@ void Scene::SetBackground(const Color& c) } } +namespace { + void c2d(const Color& c, unsigned char* d) { + d[0]=static_cast<unsigned char>(c.GetRed()*255.0); + d[1]=static_cast<unsigned char>(c.GetGreen()*255.0); + d[2]=static_cast<unsigned char>(c.GetBlue()*255.0); + } +} + +void Scene::set_bg() +{ + static std::vector<unsigned char> data; + static const unsigned int grad_steps=64; + if(bg_mode_==1) { + LOG_DEBUG("Scene: setting background gradient"); + // gradient + glBindTexture(GL_TEXTURE_2D, bg_tex_); + data.resize(3*grad_steps); + float tf=1.0/static_cast<float>(grad_steps-1); + for(size_t i=0;i<grad_steps;++i) { + Color col=bg_grad_.GetColorAt(static_cast<float>(i)*tf); + c2d(col,&data[i*3]); + } + glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,1,grad_steps,0,GL_RGB,GL_UNSIGNED_BYTE,&data[0]); + } else if(bg_mode_==2) { + LOG_DEBUG("Scene: setting background bitmap"); + // bitmap + glBindTexture(GL_TEXTURE_2D, bg_tex_); + if(bg_bm_.channels==1) { + glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,bg_bm_.width,bg_bm_.height,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,bg_bm_.data.get()); + } else if(bg_bm_.channels==3) { + glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,bg_bm_.width,bg_bm_.height,0,GL_RGB,GL_UNSIGNED_BYTE,bg_bm_.data.get()); + } else if(bg_bm_.channels==4) { + glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,bg_bm_.width,bg_bm_.height,0,GL_RGBA,GL_UNSIGNED_BYTE,bg_bm_.data.get()); + } else { + LOG_ERROR("Scene::SetBackground: unsupported bitmap channel count of " << bg_bm_.channels); + } + } +} + +void Scene::SetBackground(const Gradient& g) +{ + bg_grad_=g; + bg_mode_=1; + update_bg_=true; + RequestRedraw(); +} + +void Scene::SetBackground(const Bitmap& bm) +{ + if(bm.width==0 || bm.height==0) { + LOG_WARNING("Scene: background bitmap has invalid size (" << bm.width << "x" << bm.height << "), ignoring"); + return; + } + bg_bm_=bm; + bg_mode_=2; + update_bg_=true; + RequestRedraw(); +} + Color Scene::GetBackground() const { return background_; @@ -579,8 +658,8 @@ Viewport Scene::GetViewport() const void Scene::SetViewport(int w, int h) { - vp_width_=w; - vp_height_=h; + vp_width_=std::max<unsigned int>(1,w); + vp_height_=std::max<unsigned int>(1,h); aspect_ratio_=static_cast<float>(w)/static_cast<float>(h); if(!gl_init_) return; glViewport(0,0,w,h); @@ -726,6 +805,7 @@ void draw_lightdir(const Vec3& ldir, const geom::Transform& tf) void Scene::RenderGL() { + check_gl_error(); // clear error flag if(auto_autoslab_ || do_autoslab_) { do_autoslab(); do_autoslab_=false; @@ -738,7 +818,7 @@ void Scene::RenderGL() } else { render_scene(); } - check_gl_error(); + check_gl_error("RenderGL()"); } void Scene::Register(GLWinBase* win) @@ -1566,9 +1646,9 @@ void Scene::Export(const String& fname, unsigned int width, LOG_ERROR("Scene: no file extension specified"); return; } - String ext = fname.substr(d_index); - if(!(ext==".png")) { - LOG_ERROR("Scene: unknown file format (" << ext << ")"); + String ext = fname.substr(d_index+1); + if(ext!="png") { + LOG_ERROR("Scene::Export: unknown file format (" << ext << ")"); return; } @@ -1602,7 +1682,7 @@ void Scene::Export(const String& fname, unsigned int width, glReadBuffer(GL_BACK); LOG_DEBUG("Scene: calling bitmap export"); - BitmapExport(fname,ext,width,height,img_data.get()); + ExportBitmap(fname,ext,width,height,img_data.get()); // only switch back if it was not on to begin with if(of_flag) { @@ -1621,8 +1701,8 @@ void Scene::Export(const String& fname, bool transparent) LOG_ERROR("Scene: no file extension specified"); return; } - String ext = fname.substr(d_index); - if(ext!=".png") { + String ext = fname.substr(d_index+1); + if(ext!="png") { LOG_ERROR("Scene: unknown file format (" << ext << ")"); return; } @@ -1644,7 +1724,7 @@ void Scene::Export(const String& fname, bool transparent) boost::shared_array<uchar> img_data(new uchar[vp[2]*vp[3]*4]); glReadPixels(0,0,vp[2],vp[3],GL_RGBA,GL_UNSIGNED_BYTE,img_data.get()); glFinish(); - BitmapExport(fname,ext,vp[2],vp[3],img_data.get()); + ExportBitmap(fname,ext,vp[2],vp[3],img_data.get()); glPixelTransferf(GL_ALPHA_BIAS, 0.0); } @@ -1867,7 +1947,7 @@ void Scene::prep_glyphs() String ost_root =GetSharedDataPath(); bf::path ost_root_dir(ost_root); bf::path tex_file(ost_root_dir / "textures/glyph_texture.png"); - Bitmap bm = BitmapImport(tex_file.string(),".png"); + Bitmap bm = ImportBitmap(tex_file.string()); if(!bm.data) return; LOG_DEBUG("Scene: importing glyph tex with id " << glyph_tex_id_); @@ -1908,6 +1988,75 @@ void Scene::prep_blur() glFlush(); } +void Scene::render_bg() +{ + if(!gl_init_) return; + if(bg_mode_!=1 && bg_mode_!=2) return; + if(update_bg_) { + set_bg(); + check_gl_error("set_bg()"); + update_bg_=false; + } + + // setup state for simple texture quad +#if OST_SHADER_SUPPORT_ENABLED + Shader::Instance().PushProgram(); + Shader::Instance().Activate(""); +#endif + glPushAttrib(GL_ALL_ATTRIB_BITS); + glPushClientAttrib(GL_ALL_ATTRIB_BITS); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_FOG); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_POINT_SMOOTH); +#if defined(OST_GL_VERSION_2_0) + glDisable(GL_MULTISAMPLE); +#endif + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0,vp_width_,0,vp_height_,-1,1); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + // draw bg texture quad + glEnable(GL_TEXTURE_2D); +#if OST_SHADER_SUPPORT_ENABLED + if(OST_GL_VERSION_2_0) { + glActiveTexture(GL_TEXTURE0); + } +#endif + glBindTexture(GL_TEXTURE_2D, bg_tex_); + // draw + glColor3f(0.0,0.0,0.0); + glBegin(GL_QUADS); + glTexCoord2f(0.0,0.0); glVertex2i(0,0); + glTexCoord2f(0.0,1.0); glVertex2i(0,vp_height_); + glTexCoord2f(1.0,1.0); glVertex2i(vp_width_,vp_height_); + glTexCoord2f(1.0,0.0); glVertex2i(vp_width_,0); + glEnd(); + + // restore all settings + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopClientAttrib(); + glPopAttrib(); +#if OST_SHADER_SUPPORT_ENABLED + Shader::Instance().PopProgram(); +#endif + check_gl_error("render_bg()"); +} + void Scene::render_scene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -1915,6 +2064,8 @@ void Scene::render_scene() glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + render_bg(); + glMultMatrix(transform_.GetTransposedMatrix().Data()); #if OST_SHADER_SUPPORT_ENABLED diff --git a/modules/gfx/src/scene.hh b/modules/gfx/src/scene.hh index 4edc6663770bbdb3c047382f04e925474bd06baf..02b3b3367b5933a10162d094bf89bc561b76a74e 100644 --- a/modules/gfx/src/scene.hh +++ b/modules/gfx/src/scene.hh @@ -43,6 +43,8 @@ #include "gfx_prim.hh" #include "povray_fw.hh" #include "exporter_fw.hh" +#include "gradient.hh" +#include "bitmap_io.hh" namespace ost { namespace gfx { @@ -333,6 +335,12 @@ class DLLEXPORT_OST_GFX Scene { /// \brief set background color void SetBackground(const Color& c); + /// \brief set background gradient + void SetBackground(const Gradient& g); + + /// \brief set background image + void SetBackground(const Bitmap& bm); + /// \brief get background color Color GetBackground() const; @@ -498,6 +506,7 @@ protected: void NodeAdded(const GfxNodeP& node); void RenderModeChanged(const String& name); + private: template <typename ACTION> @@ -568,6 +577,13 @@ private: Real stereo_iod_,stereo_distance_; unsigned int scene_left_tex_; unsigned int scene_right_tex_; + unsigned int bg_mode_; + bool update_bg_; + Gradient bg_grad_; + Bitmap bg_bm_; + unsigned int bg_tex_; + + void set_near(float n); void set_far(float f); @@ -576,10 +592,11 @@ private: void prep_glyphs(); void prep_blur(); void stereo_projection(int view); + void render_bg(); void render_scene(); void render_glow(); void render_stereo(); - + void set_bg(); void do_autoslab(); bool IsNameAvailable(const String& name) const;