#include #include #include #include #include #include #include #include #include #include #ifndef WIN32 #define WEAK __attribute__ ((weak)) #else #define WEAK #endif OSMesaContext ctx = 0; void *buffer = 0; int width = -1; int height = -1; bool upscale = false; class scene_t : public Base { public: std::list scene; String filename, tmp_filename; };void empty_scene(scene_t scene) { while (scene.scene.begin() != scene.scene.end()) { scene.scene.pop_front(); } } scene_t * init_OSMesa_context(scene_t * scene, int _width, int _height) { scene_t * r = scene; if ((width > 2048) || (height > 2048)) { printf("Image too wide!\n"); return NULL; } if (!r) r = new scene_t(); glPushAttrib(GL_ALL_ATTRIB_BITS); if ((width == _width) && (height == _height)) { return r; } width = _width; height = _height; /* Bind the buffer to the context and make it current */ if (!OSMesaMakeCurrent(ctx, buffer, GL_UNSIGNED_BYTE, width, height)) { printf("OSMesaMakeCurrent (8 bits/channel) failed!\n"); delete r; return NULL; } return r; } void init_OSMesa() { const GLint z = 32, stencil = 0, accum = 0; ctx = OSMesaCreateContextExt(OSMESA_BGRA, z, stencil, accum, NULL); if (!ctx) { printf("OSMesaCreateContextExt() failed!\n"); return; } buffer = malloc(2048 * 2048 * 4); if (!buffer) { printf("Alloc image buffer failed!\n"); return; } delete init_OSMesa_context(0, 300, 300); glPopAttrib(); } void flip_scene(scene_t * scene, const char * buffer, int width, int height, bool upscale) { /* Make sure buffered commands are finished! */ glFinish(); Magick::Image i(width, height, "BGRA", Magick::CharPixel, buffer); i.flip(); i.animationDelay(6); i.opacity(0); if (upscale) { i.resize(Magick::Geometry(width / 2, height / 2)); } scene->scene.push_back(i); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void * dump_scene_threaded(void * arg) { scene_t * scene = (scene_t *) arg; char fname[2049]; writeImages(scene->scene.begin(), scene->scene.end(), scene->tmp_filename.to_charp()); unlink(scene->filename.to_charp()); rename(scene->tmp_filename.to_charp(), scene->filename.to_charp()); delete scene; pthread_exit(0); } void dump_scene(scene_t * scene, const String & filename, Handle * out, const char * buffer, int width, int height, bool upscale) { if (scene->scene.begin() == scene->scene.end()) flip_scene(scene, buffer, width, height, upscale); if (out) { Magick::Blob b; scene->scene.begin()->magick("JPEG"); scene->scene.begin()->quality(95); writeImages(scene->scene.begin(), scene->scene.end(), &b); out->write(b.data(), b.length()); delete scene; } else { pthread_t thread; scene->filename = filename; scene->tmp_filename = "tmp-" + filename; if (pthread_create(&thread, NULL, dump_scene_threaded, scene) == 0) { pthread_detach(thread); } } glPopAttrib(); return; } class plugin_osmesa : public Base { }; class Luaplugin_osmesa : public LuaObject { public: static void pushstatics(Lua *) throw (GeneralException); protected: virtual void pushmembers(Lua *); }; enum plugin_osmesa_functions_t { PLUGIN_OSMESA_INITOSMESA, PLUGIN_OSMESA_FLIPSCENE, PLUGIN_OSMESA_DUMPSCENE, PLUGIN_OSMESA_LOADTEX, }; struct lua_functypes_t plugin_osmesa_functions[] = { { PLUGIN_OSMESA_INITOSMESA, "InitOSMesa", 3, 4, { BLUA_USERDATA | BLUA_NIL, BLUA_NUMBER, BLUA_NUMBER, BLUA_BOOLEAN } }, { PLUGIN_OSMESA_FLIPSCENE, "FlipScene", 1, 1, { BLUA_USERDATA } }, { PLUGIN_OSMESA_DUMPSCENE, "DumpScene", 2, 2, { BLUA_USERDATA, BLUA_STRING | BLUA_OBJECT } }, { PLUGIN_OSMESA_LOADTEX, "LoadTex", 1, 1, { BLUA_STRING } }, { -1, 0, 0, 0, 0 } }; class sLua_plugin_osmesa : public Base { public: DECLARE_FUNCTION(plugin_osmesa, PLUGIN_OSMESA_INITOSMESA); DECLARE_FUNCTION(plugin_osmesa, PLUGIN_OSMESA_FLIPSCENE); DECLARE_FUNCTION(plugin_osmesa, PLUGIN_OSMESA_DUMPSCENE); DECLARE_FUNCTION(plugin_osmesa, PLUGIN_OSMESA_LOADTEX); private: static int plugin_osmesa_proceed(Lua * L, int n, plugin_osmesa * obj, int caller); static int plugin_osmesa_proceed_statics(Lua * L, int n, int caller); }; void Luaplugin_osmesa::pushmembers(Lua * L) { } void Luaplugin_osmesa::pushstatics(Lua * L) throw (GeneralException) { //CHECK_METHODS(plugin_osmesa); CHECK_FUNCTIONS(plugin_osmesa); PUSH_FUNCTION(plugin_osmesa, PLUGIN_OSMESA_INITOSMESA); PUSH_FUNCTION(plugin_osmesa, PLUGIN_OSMESA_FLIPSCENE); PUSH_FUNCTION(plugin_osmesa, PLUGIN_OSMESA_DUMPSCENE); PUSH_FUNCTION(plugin_osmesa, PLUGIN_OSMESA_LOADTEX); } int sLua_plugin_osmesa::plugin_osmesa_proceed(Lua * L, int n, plugin_osmesa * obj, int caller) { return 0; } int sLua_plugin_osmesa::plugin_osmesa_proceed_statics(Lua * L, int n, int caller) { int _width, _height, r = 0; String filename; const char * t; DDS_IMAGE_DATA * dds; scene_t * scene = 0; switch (caller) { case PLUGIN_OSMESA_INITOSMESA: if (!L->isnil(1)) { scene = (scene_t *) L->touserdata(1); } _width = L->tonumber(2); _height = L->tonumber(3); if (n == 4) { upscale = L->toboolean(4); } else { upscale = false; } L->push(init_OSMesa_context(scene, _width, _height)); r = 1; break; case PLUGIN_OSMESA_FLIPSCENE: flip_scene((scene_t *) L->touserdata(1), (char *) buffer, width, height, upscale); break; case PLUGIN_OSMESA_DUMPSCENE: if (L->isstring(2)) { filename = L->tostring(2); dump_scene((scene_t *) L->touserdata(1), filename, 0, (char *) buffer, width, height, upscale); } else { Handle * t = (Handle *) LuaObject::getme(L, 2); dump_scene((scene_t *) L->touserdata(1), "", t, (char *) buffer, width, height, upscale); } break; case PLUGIN_OSMESA_LOADTEX: filename = L->tostring(1); t = filename.to_charp(); dds = loadDDSTextureFile(t); L->push((lua_Number) loadCompressedTexture(dds)); L->push((lua_Number) dds->width); L->push((lua_Number) dds->height); destroyDDS(dds); r = 3; break; } return r; } static void _init_plugin(Lua * L) { init_OSMesa(); Luaplugin_osmesa::pushstatics(L); } extern "C" { WEAK void init_plugin(Lua * L) { _init_plugin(L); } void luaosmesa_init(Lua * L) { _init_plugin(L); } }