Code: Select all
/** Example 027 Helloworld_Android
This example shows a simple application for Android.
Modified to disable mipmaps and optimize texture display.
*/
#include <irrlicht/irrlicht.h>
#ifdef _IRR_ANDROID_PLATFORM_
#include <android_native_app_glue/android_native_app_glue.h>
#include "android_tools.h"
#include "android/window.h"
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
// GUI Element IDs
enum GUI_IDS
{
GUI_INFO_FPS,
GUI_IRR_LOGO,
};
//=============================================================================
// Event Receiver Class
//=============================================================================
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(android_app* app)
: Device(0), AndroidApp(app), SpriteToMove(0), TouchID(-1)
{
}
void Init(IrrlichtDevice *device)
{
Device = device;
}
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_TOUCH_INPUT_EVENT)
{
// Fake mouse-events for GUI compatibility
SEvent fakeMouseEvent;
fakeMouseEvent.EventType = EET_MOUSE_INPUT_EVENT;
fakeMouseEvent.MouseInput.X = event.TouchInput.X;
fakeMouseEvent.MouseInput.Y = event.TouchInput.Y;
fakeMouseEvent.MouseInput.Shift = false;
fakeMouseEvent.MouseInput.Control = false;
fakeMouseEvent.MouseInput.ButtonStates = 0;
fakeMouseEvent.MouseInput.Event = EMIE_COUNT;
switch (event.TouchInput.Event)
{
case ETIE_PRESSED_DOWN:
{
if (TouchID == -1)
{
fakeMouseEvent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
if (Device)
{
position2d<s32> touchPoint(event.TouchInput.X, event.TouchInput.Y);
IGUIElement * logo = Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_IRR_LOGO);
if (logo && logo->isPointInside(touchPoint))
{
TouchID = event.TouchInput.ID;
SpriteToMove = logo;
SpriteStartRect = SpriteToMove->getRelativePosition();
TouchStartPos = touchPoint;
}
}
}
break;
}
case ETIE_MOVED:
if (TouchID == event.TouchInput.ID)
{
fakeMouseEvent.MouseInput.Event = EMIE_MOUSE_MOVED;
fakeMouseEvent.MouseInput.ButtonStates = EMBSM_LEFT;
if (SpriteToMove && TouchID == event.TouchInput.ID)
{
position2d<s32> touchPoint(event.TouchInput.X, event.TouchInput.Y);
MoveSprite(touchPoint);
}
}
break;
case ETIE_LEFT_UP:
if (TouchID == event.TouchInput.ID)
{
fakeMouseEvent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
if (SpriteToMove)
{
TouchID = -1;
position2d<s32> touchPoint(event.TouchInput.X, event.TouchInput.Y);
MoveSprite(touchPoint);
SpriteToMove = 0;
}
}
break;
default:
break;
}
if (fakeMouseEvent.MouseInput.Event != EMIE_COUNT && Device)
{
Device->postEventFromUser(fakeMouseEvent);
}
}
else if (event.EventType == EET_GUI_EVENT)
{
// Handle soft keyboard visibility
switch(event.GUIEvent.EventType)
{
case EGET_EDITBOX_ENTER:
if (event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX)
{
if(Device->getGUIEnvironment())
Device->getGUIEnvironment()->setFocus(NULL);
android::setSoftInputVisibility(AndroidApp, false);
}
break;
case EGET_ELEMENT_FOCUS_LOST:
if (event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX)
{
android::setSoftInputVisibility(AndroidApp, false);
}
break;
case EGET_ELEMENT_FOCUSED:
if (event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX)
{
android::setSoftInputVisibility(AndroidApp, true);
}
break;
default:
break;
}
}
return false;
}
void MoveSprite(const irr::core::position2d<irr::s32> &touchPos)
{
irr::core::position2d<irr::s32> move(touchPos - TouchStartPos);
SpriteToMove->setRelativePosition(SpriteStartRect.UpperLeftCorner + move);
}
private:
IrrlichtDevice * Device;
android_app* AndroidApp;
gui::IGUIElement * SpriteToMove;
core::rect<s32> SpriteStartRect;
core::position2d<irr::s32> TouchStartPos;
s32 TouchID;
};
//=============================================================================
// Main Loop
//=============================================================================
void mainloop(IrrlichtDevice *device, IGUIStaticText * infoText)
{
u32 loop = 0;
static u32 runCounter = 0;
while(device->run())
{
if (device->isWindowActive())
{
// Force full screen viewport
IVideoDriver* driver = device->getVideoDriver();
if (driver)
{
core::dimension2d<u32> screenSize = driver->getScreenSize();
driver->setViewPort(core::rect<s32>(0, 0, screenSize.Width, screenSize.Height));
}
// Update FPS counter
if (infoText)
{
stringw str = L"FPS:";
str += (s32)device->getVideoDriver()->getFPS();
str += L" r:";
str += runCounter;
str += L" l:";
str += loop;
infoText->setText(str.c_str());
}
device->getVideoDriver()->beginScene(true, true, SColor(0,100,100,100));
device->getSceneManager()->drawAll();
device->getGUIEnvironment()->drawAll();
device->getVideoDriver()->endScene();
}
device->yield();
++runCounter;
++loop;
}
}
//=============================================================================
// Configure Texture Settings - DISABLE MIPMAPS
//=============================================================================
void configureTextureSettings(IVideoDriver* driver)
{
if (!driver) return;
// *** DISABLE MIPMAPS GLOBALLY ***
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
// Note: ETCF_ALLOW_ANISOTROPIC_FILTER doesn't exist in some versions
// Use material flags instead for anisotropic filtering
}
//=============================================================================
// Create GUI Elements
//=============================================================================
void createGUI(IGUIEnvironment* guienv, IVideoDriver* driver,
IGUIStaticText** outInfoText, IGUIImage** outLogo,
s32 windowWidth, const stringc& mediaPath)
{
if (!guienv || !driver) return;
// Create info text
*outInfoText = guienv->addStaticText(
L"Loading...",
rect<s32>(5, 5, 635, 35),
false, false, 0, GUI_INFO_FPS
);
// Create edit box
guienv->addEditBox(L"", rect<s32>(5, 40, 475, 80));
// Create Irrlicht logo without mipmaps
// Note: getTexture with bool parameter may not be available in all versions
ITexture* logoTexture = driver->getTexture((mediaPath + "irrlichtlogo3.png").c_str());
if (logoTexture)
{
*outLogo = guienv->addImage(
logoTexture,
core::position2d<s32>(5, 85),
true, 0, GUI_IRR_LOGO
);
// Scale logo for high-res displays
if (*outLogo)
{
s32 minLogoWidth = windowWidth / 3;
if ((*outLogo)->getRelativePosition().getWidth() < minLogoWidth)
{
(*outLogo)->setScaleImage(true);
core::rect<s32> logoPos((*outLogo)->getRelativePosition());
f32 scale = (f32)minLogoWidth / (f32)logoPos.getWidth();
logoPos.LowerRightCorner.X = logoPos.UpperLeftCorner.X + minLogoWidth;
logoPos.LowerRightCorner.Y = logoPos.UpperLeftCorner.Y +
(s32)((f32)logoPos.getHeight() * scale);
(*outLogo)->setRelativePosition(logoPos);
}
}
}
}
//=============================================================================
// Create 3D Scene with Character
//=============================================================================
void createScene(ISceneManager* smgr, IVideoDriver* driver,
ILogger* logger, const stringc& mediaPath,
s32 windowWidth, s32 windowHeight)
{
if (!smgr || !driver) return;
// Load character mesh
IAnimatedMesh* mesh = smgr->getMesh((mediaPath + "dwarf.x").c_str());
if (!mesh)
{
logger->log("Failed to load dwarf.x mesh", ELL_ERROR);
return;
}
// Create character node
IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
if (!node)
{
logger->log("Failed to create animated mesh scene node", ELL_ERROR);
return;
}
// Load texture
ITexture* texture = driver->getTexture((mediaPath + "dwarf.jpg").c_str());
ITexture* texture2 = driver->getTexture((mediaPath + "axe.jpg").c_str());
if (texture&&texture2)
{
// Apply texture to material
node->setMaterialTexture(0, texture);
node->setMaterialTexture(1, texture2);
node->setMaterialFlag(video::EMF_LIGHTING, false);
// Configure material for optimal display without mipmaps
SMaterial& material = node->getMaterial(0);
material.TextureLayer[0].BilinearFilter = false;
material.TextureLayer[0].TrilinearFilter = false;
material.TextureLayer[0].AnisotropicFilter = 0;
material.UseMipMaps = false;
logger->log("Texture dwarf.jpg loaded successfully without mipmaps", ELL_INFORMATION);
}
else
{
logger->log("Failed to load dwarf.jpg texture", ELL_ERROR);
}
// Configure character
node->setScale(core::vector3df(0.4f, 0.4f, 0.4f));
node->setAnimationSpeed(30);
node->setLoopMode(true);
// Add ambient light
smgr->setAmbientLight(video::SColorf(0.8f, 0.8f, 0.8f, 1.0f));
// Create camera with correct aspect ratio
ICameraSceneNode* camera = smgr->addCameraSceneNode(
0,
vector3df(0, 15, -40), // Camera position
vector3df(0, 10, 0) // Look-at target
);
if (camera)
{
f32 aspectRatio = (f32)windowWidth / (f32)windowHeight;
camera->setAspectRatio(aspectRatio);
camera->setFOV(core::PI / 3.5f);
// Log using string concatenation
core::stringc logMsg = "Camera configured with aspect ratio: ";
logMsg += aspectRatio;
logger->log(logMsg.c_str(), ELL_INFORMATION);
}
}
//=============================================================================
// Main Application Entry Point
//=============================================================================
void android_main(android_app* app)
{
// Make sure glue isn't stripped
app_dummy();
// Create event receiver
MyEventReceiver receiver(app);
// Configure device creation parameters
SIrrlichtCreationParameters param;
param.DriverType = EDT_OGLES2; // Use OpenGL ES 2.0
param.WindowSize = dimension2d<u32>(0, 0); // Auto-detect size
param.Fullscreen = true; // Full screen
param.PrivateData = app;
param.Bits = 24;
param.ZBufferBits = 16;
param.AntiAlias = 0;
param.EventReceiver = &receiver;
#ifndef _DEBUG
param.LoggingLevel = ELL_NONE;
#endif
// Create Irrlicht device
IrrlichtDevice *device = createDeviceEx(param);
if (!device)
return;
// Initialize event receiver
receiver.Init(device);
// Get core components
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
ILogger* logger = device->getLogger();
IFileSystem* fs = device->getFileSystem();
// Configure texture settings - DISABLE MIPMAPS
configureTextureSettings(driver);
logger->log("Mipmaps disabled globally", ELL_INFORMATION);
// Get window and display information
ANativeWindow* nativeWindow = static_cast<ANativeWindow*>(
driver->getExposedVideoData().OGLESAndroid.Window
);
int32_t windowWidth = ANativeWindow_getWidth(app->window);
int32_t windowHeight = ANativeWindow_getHeight(app->window);
// Get display metrics
irr::android::SDisplayMetrics displayMetrics;
memset(&displayMetrics, 0, sizeof(displayMetrics));
irr::android::getDisplayMetrics(app, displayMetrics);
// Log system information using string concatenation
core::stringc logMsg;
logMsg = "Window: ";
logMsg += windowWidth;
logMsg += "x";
logMsg += windowHeight;
logMsg += ", Display: ";
logMsg += displayMetrics.widthPixels;
logMsg += "x";
logMsg += displayMetrics.heightPixels;
logMsg += ", DPI: ";
logMsg += displayMetrics.xdpi;
logger->log(logMsg.c_str(), ELL_INFORMATION);
// Set initial viewport
core::dimension2d<s32> dim(driver->getScreenSize());
driver->setViewPort(core::rect<s32>(0, 0, dim.Width, dim.Height));
logger->log("Viewport set to full screen", ELL_INFORMATION);
// Configure Android assets file system
stringc mediaPath = "media/";
for (u32 i = 0; i < fs->getFileArchiveCount(); ++i)
{
IFileArchive* archive = fs->getFileArchive(i);
if (archive->getType() == EFAT_ANDROID_ASSET)
{
archive->addDirectoryToFileList(mediaPath);
logger->log("Added media directory to asset archive", ELL_INFORMATION);
break;
}
}
// Set font based on DPI
IGUISkin* skin = guienv->getSkin();
IGUIFont* font = 0;
if (displayMetrics.xdpi < 100)
font = guienv->getFont((mediaPath + "fonthaettenschweiler.bmp").c_str());
else
font = guienv->getFont((mediaPath + "bigfont.png").c_str());
if (font)
skin->setFont(font);
// Create GUI elements
IGUIStaticText* infoText = nullptr;
IGUIImage* logo = nullptr;
createGUI(guienv, driver, &infoText, &logo, windowWidth, mediaPath);
// Create 3D scene
createScene(smgr, driver, logger, mediaPath, windowWidth, windowHeight);
// Enter main loop
logger->log("Entering main loop", ELL_INFORMATION);
mainloop(device, infoText);
// Cleanup
logger->log("Cleaning up", ELL_INFORMATION);
device->setEventReceiver(0);
device->closeDevice();
device->drop();
}
#endif // defined(_IRR_ANDROID_PLATFORM_)