Alright, after more digging I finally came across a more definitive solution. I posted the solution in my forum post on the issue on cocos2d-x's forum, but I'll post it here too just in case.
So the real issue is that on iOS devices, device orientation isn't reported correctly, and on Landscape mode, the screen coordinates will have the width and height values swapped. To fix that, I basically used the solution described by Tim Closs in this forum post for rotating the projection matrix, with minor tweaks:
New method in AppDelegate:
/**
* Update the projection, based on an input angle, and store back the new w, h
*
* @param angle 0, 90, 180 or 270
* @param w the new width of the virtual display
* @param h the new height of the virtual display
*/
virtual void updateProjection(float angle, float& w, float& h);
Method implementation:
void AppDelegate::updateProjection(float angle, float& w, float& h) {
if (IwGLGetInt(IW_GL_VIRTUAL_WIDTH) >= 0) {
w = (float)IwGLGetInt(IW_GL_VIRTUAL_WIDTH);
h = (float)IwGLGetInt(IW_GL_VIRTUAL_HEIGHT);
}
else {
w = (float)s3eSurfaceGetInt(S3E_SURFACE_WIDTH);
h = (float)s3eSurfaceGetInt(S3E_SURFACE_HEIGHT);
}
if ((angle == 90.0f) || (angle == 270.0f)) {
// Swap w and h
float oh = h;
h = w;
w = oh;
}
CCEGLView::sharedOpenGLView()->setFrameSize(w, h);
kmGLMatrixMode(KM_GL_PROJECTION);
kmGLLoadIdentity();
kmGLRotatef((float)angle, 0, 0, 1);
kmMat4 orthoMatrix;
kmMat4OrthographicProjection(&orthoMatrix, 0, w, 0, h, -1024, 1024 );
kmGLMultMatrix(&orthoMatrix);
kmGLMatrixMode(KM_GL_MODELVIEW);
kmGLLoadIdentity();
}
Call to AppDelegate::updateProjection in AppDelegate::applicationDidFinishLaunching:
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
CCDirector *pDirector = CCDirector::sharedDirector();
pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());
pDirector->setProjection(kCCDirectorProjection2D);
// Set projection
float w, h;
float angle = s3eSurfaceGetInt(S3E_SURFACE_DEVICE_BLIT_DIRECTION) * 90.0f;
// Workaround for ios devices, force rotation
int os = s3eDeviceGetInt(S3E_DEVICE_OS);
if (os == S3E_OS_ID_IPHONE || os == S3E_OS_ID_OSX)
angle = 90;
updateProjection(angle, w, h);
// Rest of method ...
}
The original solution also defined the virtual dimensions on marmalade's icf file, thus overriding cocos2d-x's scaling system, but I chose to stick with what cocos2d-x provides and it works just as well. The biggest difference was explicitely setting the angle to 90 for all iOS devices, since the original problem is that landscape orientation wasn't being detected in the first place.
Also it should be noted that after implementing this solution, all my other workarounds for this issue became unnecessary, thus had to be removed for the correct behavior to take place.
Hope this can be of help to someone!