X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftile.cpp;h=17ec51614fe1265eaf8f2cf72762c875d6060004;hb=37b7f094e3ea502339794f64e8bad22444c6fb54;hp=027e3add771d3ed05ea5977b2b0964136b9b7a4f;hpb=96c34d369e71e25299eccc1527ae5463ea5219e3;p=oweals%2Fminetest.git diff --git a/src/tile.cpp b/src/tile.cpp index 027e3add7..17ec51614 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -32,6 +32,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/thread.h" #include "util/numeric.h" +#ifdef __ANDROID__ +#include +#endif + /* A cache from texture name to texture path */ @@ -58,7 +62,7 @@ static bool replace_ext(std::string &path, const char *ext) last_dot_i = i; break; } - + if(path[i] == '\\' || path[i] == '/') break; } @@ -97,7 +101,7 @@ std::string getImagePath(std::string path) return path; } while((++ext) != NULL); - + return ""; } @@ -120,7 +124,7 @@ std::string getTexturePath(const std::string &filename) bool incache = g_texturename_to_path_cache.get(filename, &fullpath); if(incache) return fullpath; - + /* Check from texture_path */ @@ -143,10 +147,10 @@ std::string getTexturePath(const std::string &filename) // Check all filename extensions. Returns "" if not found. fullpath = getImagePath(testpath); } - + // Add to cache (also an empty result is cached) g_texturename_to_path_cache.set(filename, fullpath); - + // Finally return it return fullpath; } @@ -164,16 +168,13 @@ struct TextureInfo { std::string name; video::ITexture *texture; - video::IImage *img; // The source image TextureInfo( const std::string &name_, - video::ITexture *texture_=NULL, - video::IImage *img_=NULL + video::ITexture *texture_=NULL ): name(name_), - texture(texture_), - img(img_) + texture(texture_) { } }; @@ -302,14 +303,14 @@ public: getTextureId("stone.png^mineral_coal.png^crack0"). */ - + /* Gets a texture id from cache or - if main thread, from getTextureIdDirect - if other thread, adds to request queue and waits for main thread */ u32 getTextureId(const std::string &name); - + /* Example names: "stone.png" @@ -363,21 +364,21 @@ public: // Processes queued texture requests from other threads. // Shall be called from the main thread. void processQueue(); - + // Insert an image into the cache without touching the filesystem. // Shall be called from the main thread. void insertSourceImage(const std::string &name, video::IImage *img); - + // Rebuild images and textures from the current set of source images // Shall be called from the main thread. void rebuildImagesAndTextures(); - + // Render a mesh to a texture. // Returns NULL if render-to-texture failed. // Shall be called from the main thread. video::ITexture* generateTextureFromMesh( const TextureFromMeshParams ¶ms); - + // Generates an image from a full string like // "stone.png^mineral_coal.png^[crack:1:0". // Shall be called from the main thread. @@ -389,12 +390,12 @@ public: bool generateImage(std::string part_of_name, video::IImage *& baseimg); private: - + // The id of the thread that is allowed to use irrlicht directly threadid_t m_main_thread; // The irrlicht device IrrlichtDevice *m_device; - + // Cache of source images // This should be only accessed from the main thread SourceImageCache m_sourcecache; @@ -409,7 +410,7 @@ private: std::map m_name_to_id; // The two former containers are behind this mutex JMutex m_textureinfo_cache_mutex; - + // Queued texture fetches (to be processed by the main thread) RequestQueue m_get_texture_queue; @@ -432,15 +433,13 @@ TextureSource::TextureSource(IrrlichtDevice *device): m_device(device) { assert(m_device); - - m_textureinfo_cache_mutex.Init(); - + m_main_thread = get_current_thread_id(); - + // Add a NULL TextureInfo as the first index, named "" m_textureinfo_cache.push_back(TextureInfo("")); m_name_to_id[""] = 0; - + // Cache some settings // Note: Since this is only done once, the game must be restarted // for these settings to take effect @@ -462,10 +461,6 @@ TextureSource::~TextureSource() //cleanup texture if (iter->texture) driver->removeTexture(iter->texture); - - //cleanup source image - if (iter->img) - iter->img->drop(); } m_textureinfo_cache.clear(); @@ -499,7 +494,7 @@ u32 TextureSource::getTextureId(const std::string &name) return n->second; } } - + /* Get texture */ @@ -512,32 +507,33 @@ u32 TextureSource::getTextureId(const std::string &name) infostream<<"getTextureId(): Queued: name=\""< result_queue; - + static ResultQueue result_queue; + // Throw a request in m_get_texture_queue.add(name, 0, 0, &result_queue); - - infostream<<"Waiting for texture from main thread, name=\"" - < + while(true) { + // Wait result for a second + GetResult result = result_queue.pop_front(1000); - - // Check that at least something worked OK - assert(result.key == name); - return result.item; + if (result.key == name) { + return result.item; + } + } } catch(ItemNotFoundException &e) { - infostream<<"Waiting for texture timed out."<=0; i--) @@ -647,9 +643,9 @@ u32 TextureSource::getTextureIdDirect(const std::string &name) < dim = ti->img->getDimension(); - - baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); + core::dimension2d dim = ti->texture->getSize(); - ti->img->copyTo( - baseimg, // target - v2s32(0,0), // position in target - core::rect(v2s32(0,0), dim) // from - ); + baseimg = driver->createImage(ti->texture,v2s32(0,0), dim); /*infostream<<"getTextureIdDirect(): Loaded \"" <addTexture(name.c_str(), baseimg); + baseimg->drop(); } - + /* Add texture to caches (add NULL textures too) */ JMutexAutoLock lock(m_textureinfo_cache_mutex); - + u32 id = m_textureinfo_cache.size(); - TextureInfo ti(name, t, baseimg); + TextureInfo ti(name, t); m_textureinfo_cache.push_back(ti); m_name_to_id[name] = id; - /*infostream<<"getTextureIdDirect(): " - <<"Returning id="< @@ -786,22 +778,16 @@ void TextureSource::processQueue() <<"name=\""< - result; - result.key = request.key; - result.callers = request.callers; - result.item = getTextureIdDirect(request.key); - - request.dest->push_back(result); + m_get_texture_queue.pushResult(request,getTextureIdDirect(request.key)); } } void TextureSource::insertSourceImage(const std::string &name, video::IImage *img) { //infostream<<"TextureSource::insertSourceImage(): name="<getVideoDriver()); m_source_image_existence.set(name, true); } @@ -811,19 +797,26 @@ void TextureSource::rebuildImagesAndTextures() JMutexAutoLock lock(m_textureinfo_cache_mutex); video::IVideoDriver* driver = m_device->getVideoDriver(); + assert(driver != 0); // Recreate textures for(u32 i=0; iname); +#ifdef __ANDROID__ + img = Align2Npot2(img,driver); + assert(img->getDimension().Height == npot2(img->getDimension().Height)); + assert(img->getDimension().Width == npot2(img->getDimension().Width)); +#endif // Create texture from resulting image video::ITexture *t = NULL; - if(img) + if(img) { t = driver->addTexture(ti->name.c_str(), img); + img->drop(); + } video::ITexture *t_old = ti->texture; // Replace texture ti->texture = t; - ti->img = img; if (t_old != 0) m_texture_trash.push_back(t_old); @@ -836,6 +829,126 @@ video::ITexture* TextureSource::generateTextureFromMesh( video::IVideoDriver *driver = m_device->getVideoDriver(); assert(driver); +#ifdef __ANDROID__ + const GLubyte* renderstr = glGetString(GL_RENDERER); + std::string renderer((char*) renderstr); + + // use no render to texture hack + if ( + (renderer.find("Adreno") != std::string::npos) || + (renderer.find("Mali") != std::string::npos) || + (renderer.find("Immersion") != std::string::npos) || + (renderer.find("Tegra") != std::string::npos) || + g_settings->getBool("inventory_image_hack") + ) { + // Get a scene manager + scene::ISceneManager *smgr_main = m_device->getSceneManager(); + assert(smgr_main); + scene::ISceneManager *smgr = smgr_main->createNewSceneManager(); + assert(smgr); + + const float scaling = 0.2; + + scene::IMeshSceneNode* meshnode = + smgr->addMeshSceneNode(params.mesh, NULL, + -1, v3f(0,0,0), v3f(0,0,0), + v3f(1.0 * scaling,1.0 * scaling,1.0 * scaling), true); + meshnode->setMaterialFlag(video::EMF_LIGHTING, true); + meshnode->setMaterialFlag(video::EMF_ANTI_ALIASING, true); + meshnode->setMaterialFlag(video::EMF_TRILINEAR_FILTER, m_setting_trilinear_filter); + meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, m_setting_bilinear_filter); + meshnode->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, m_setting_anisotropic_filter); + + scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0, + params.camera_position, params.camera_lookat); + // second parameter of setProjectionMatrix (isOrthogonal) is ignored + camera->setProjectionMatrix(params.camera_projection_matrix, false); + + smgr->setAmbientLight(params.ambient_light); + smgr->addLightSceneNode(0, + params.light_position, + params.light_color, + params.light_radius*scaling); + + core::dimension2d screen = driver->getScreenSize(); + + // Render scene + driver->beginScene(true, true, video::SColor(0,0,0,0)); + driver->clearZBuffer(); + smgr->drawAll(); + + core::dimension2d partsize(screen.Width * scaling,screen.Height * scaling); + + irr::video::IImage* rawImage = + driver->createImage(irr::video::ECF_A8R8G8B8, partsize); + + u8* pixels = static_cast(rawImage->lock()); + if (!pixels) + { + rawImage->drop(); + return NULL; + } + + core::rect source( + screen.Width /2 - (screen.Width * (scaling / 2)), + screen.Height/2 - (screen.Height * (scaling / 2)), + screen.Width /2 + (screen.Width * (scaling / 2)), + screen.Height/2 + (screen.Height * (scaling / 2)) + ); + + glReadPixels(source.UpperLeftCorner.X, source.UpperLeftCorner.Y, + partsize.Width, partsize.Height, GL_RGBA, + GL_UNSIGNED_BYTE, pixels); + + driver->endScene(); + + // Drop scene manager + smgr->drop(); + + unsigned int pixelcount = partsize.Width*partsize.Height; + + u8* runptr = pixels; + for (unsigned int i=0; i < pixelcount; i++) { + + u8 B = *runptr; + u8 G = *(runptr+1); + u8 R = *(runptr+2); + u8 A = *(runptr+3); + + //BGRA -> RGBA + *runptr = R; + runptr ++; + *runptr = G; + runptr ++; + *runptr = B; + runptr ++; + *runptr = A; + runptr ++; + } + + video::IImage* inventory_image = + driver->createImage(irr::video::ECF_A8R8G8B8, params.dim); + + rawImage->copyToScaling(inventory_image); + rawImage->drop(); + + video::ITexture *rtt = driver->addTexture(params.rtt_texture_name.c_str(), inventory_image); + inventory_image->drop(); + + if (rtt == NULL) { + errorstream << "TextureSource::generateTextureFromMesh(): failed to recreate texture from image: " << params.rtt_texture_name << std::endl; + return NULL; + } + + driver->makeColorKeyTexture(rtt, v2s32(0,0)); + + if(params.delete_texture_on_shutdown) + m_texture_trash.push_back(rtt); + + return rtt; + } +#endif + if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false) { static bool warned = false; @@ -860,7 +973,12 @@ video::ITexture* TextureSource::generateTextureFromMesh( } // Set render target - driver->setRenderTarget(rtt, false, true, video::SColor(0,0,0,0)); + if (!driver->setRenderTarget(rtt, false, true, video::SColor(0,0,0,0))) { + driver->removeTexture(rtt); + errorstream<<"TextureSource::generateTextureFromMesh(): " + <<"failed to set render target"<getSceneManager(); @@ -868,7 +986,9 @@ video::ITexture* TextureSource::generateTextureFromMesh( scene::ISceneManager *smgr = smgr_main->createNewSceneManager(); assert(smgr); - scene::IMeshSceneNode* meshnode = smgr->addMeshSceneNode(params.mesh, NULL, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true); + scene::IMeshSceneNode* meshnode = + smgr->addMeshSceneNode(params.mesh, NULL, + -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true); meshnode->setMaterialFlag(video::EMF_LIGHTING, true); meshnode->setMaterialFlag(video::EMF_ANTI_ALIASING, true); meshnode->setMaterialFlag(video::EMF_TRILINEAR_FILTER, m_setting_trilinear_filter); @@ -891,11 +1011,6 @@ video::ITexture* TextureSource::generateTextureFromMesh( smgr->drawAll(); driver->endScene(); - // NOTE: The scene nodes should not be dropped, otherwise - // smgr->drop() segfaults - /*cube->drop(); - camera->drop(); - light->drop();*/ // Drop scene manager smgr->drop(); @@ -938,14 +1053,14 @@ video::IImage* TextureSource::generateImageFromScratch(std::string name) base_image_name = name.substr(0, last_separator_position); baseimg = generateImageFromScratch(base_image_name); } - + /* Parse out the last part of the name of the image and act according to it */ std::string last_part_of_name = name.substr(last_separator_position+1); - + // Generate image according to part of name if(!generateImage(last_part_of_name, baseimg)) { @@ -954,10 +1069,61 @@ video::IImage* TextureSource::generateImageFromScratch(std::string name) < +/** + * Check and align image to npot2 if required by hardware + * @param image image to check for npot2 alignment + * @param driver driver to use for image operations + * @return image or copy of image aligned to npot2 + */ +video::IImage * Align2Npot2(video::IImage * image, + video::IVideoDriver* driver) +{ + if(image == NULL) { + return image; + } + + core::dimension2d dim = image->getDimension(); + + std::string extensions = (char*) glGetString(GL_EXTENSIONS); + if (extensions.find("GL_OES_texture_npot") != std::string::npos) { + return image; + } + + unsigned int height = npot2(dim.Height); + unsigned int width = npot2(dim.Width); + + if ((dim.Height == height) && + (dim.Width == width)) { + return image; + } + + if (dim.Height > height) { + height *= 2; + } + + if (dim.Width > width) { + width *= 2; + } + + video::IImage *targetimage = + driver->createImage(video::ECF_A8R8G8B8, + core::dimension2d(width, height)); + + if (targetimage != NULL) { + image->copyToScaling(targetimage); + } + image->drop(); + return targetimage; +} + +#endif + bool TextureSource::generateImage(std::string part_of_name, video::IImage *& baseimg) { video::IVideoDriver* driver = m_device->getVideoDriver(); @@ -967,14 +1133,22 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas if(part_of_name.size() == 0 || part_of_name[0] != '[') { video::IImage *image = m_sourcecache.getOrLoad(part_of_name, m_device); - - if(image == NULL) - { - if(part_of_name != ""){ - errorstream<<"generateImage(): Could not load image \"" +#ifdef __ANDROID__ + image = Align2Npot2(image,driver); +#endif + if (image == NULL) { + if (part_of_name != "") { + if (part_of_name.find("_normal.png") == std::string::npos){ + errorstream<<"generateImage(): Could not load image \"" < dim = image->getDimension(); @@ -1037,7 +1211,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas /*infostream<<"generateImage(): generating special " <<"modification \""< dim = baseimg->getDimension(); - + // Set alpha to full for(u32 y=0; y dim = baseimg->getDimension(); - + /*video::IImage *oldbaseimg = baseimg; baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); oldbaseimg->copyTo(baseimg); @@ -1284,7 +1458,16 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas video::IImage *img_right = generateImageFromScratch(imagename_right); assert(img_top && img_left && img_right); +#ifdef __ANDROID__ + assert(img_top->getDimension().Height == npot2(img_top->getDimension().Height)); + assert(img_top->getDimension().Width == npot2(img_top->getDimension().Width)); + + assert(img_left->getDimension().Height == npot2(img_left->getDimension().Height)); + assert(img_left->getDimension().Width == npot2(img_left->getDimension().Width)); + assert(img_right->getDimension().Height == npot2(img_right->getDimension().Height)); + assert(img_right->getDimension().Width == npot2(img_right->getDimension().Width)); +#endif // Create textures from images video::ITexture *texture_top = driver->addTexture( (imagename_top + "__temp__").c_str(), img_top); @@ -1298,7 +1481,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas img_top->drop(); img_left->drop(); img_right->drop(); - + /* Draw a cube mesh into a render target texture */ @@ -1328,9 +1511,9 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas params.light_position.set(10, 100, -50); params.light_color.set(1.0, 0.5, 0.5, 0.5); params.light_radius = 1000; - + video::ITexture *rtt = generateTextureFromMesh(params); - + // Drop mesh cube->drop(); @@ -1338,7 +1521,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas driver->removeTexture(texture_top); driver->removeTexture(texture_left); driver->removeTexture(texture_right); - + if(rtt == NULL) { baseimg = generateImageFromScratch(imagename_top); @@ -1413,7 +1596,7 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas <<"\", cancelling."<getDimension(); frame_size.Y /= frame_count; @@ -1499,7 +1682,7 @@ static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst, } static void draw_crack(video::IImage *crack, video::IImage *dst, - bool use_overlay, u32 frame_count, u32 progression, + bool use_overlay, s32 frame_count, s32 progression, video::IVideoDriver *driver) { // Dimension of destination image @@ -1507,11 +1690,11 @@ static void draw_crack(video::IImage *crack, video::IImage *dst, // Dimension of original image core::dimension2d dim_crack = crack->getDimension(); // Count of crack stages - u32 crack_count = dim_crack.Height / dim_crack.Width; + s32 crack_count = dim_crack.Height / dim_crack.Width; // Limit frame_count - if(frame_count > dim_dst.Height) + if(frame_count > (s32) dim_dst.Height) frame_count = dim_dst.Height; - if(frame_count == 0) + if(frame_count < 1) frame_count = 1; // Limit progression if(progression > crack_count-1) @@ -1543,7 +1726,7 @@ static void draw_crack(video::IImage *crack, video::IImage *dst, // Scale crack image by copying crack_cropped->copyToScaling(crack_scaled); // Copy or overlay crack image onto each frame - for(u32 i = 0; i < frame_count; ++i) + for(s32 i = 0; i < frame_count; ++i) { v2s32 dst_pos(0, dim_crack_scaled.Height * i); if(use_overlay) @@ -1572,7 +1755,7 @@ void brighten(video::IImage *image) { if(image == NULL) return; - + core::dimension2d dim = image->getDimension(); for(u32 y=0; y srcdim = src->getDimension(); core::dimension2d dstdim = dst->getDimension();