Redo the DPI/Density code. It now makes sense.

This commit is contained in:
Henrik Rydgard 2012-07-15 17:04:27 +02:00
parent 1254fe414c
commit 5a6622eb37
9 changed files with 108 additions and 70 deletions

View file

@ -21,6 +21,7 @@
#include "input/input_state.h"
#include "audio/mixer.h"
#include "math/math_util.h"
#include "net/resolve.h"
#include "android/native_audio.h"
#define coord_xres 480
@ -70,8 +71,8 @@ void LaunchEmail(const char *email_address) {
// Remember that all of these need initialization on init! The process
// may be reused when restarting the game. Globals are DANGEROUS.
float xscale = 1;
float yscale = 1;
float dp_xscale = 1;
float dp_yscale = 1;
InputState input_state;
@ -104,24 +105,6 @@ extern "C" void Java_com_turboviking_libnative_NativeApp_init
jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jinstallID, jboolean juseNativeAudio) {
jniEnvUI = env;
pixel_xres = xxres;
pixel_yres = yyres;
g_dpi = dpi;
// We default to 160 dpi and all our UI code is written to assume it. (DENSITY_MEDIUM).
g_xres = xxres * 160 / dpi;
g_yres = yyres * 160 / dpi;
use_native_audio = juseNativeAudio;
if (g_xres < g_yres)
{
// Portrait - let's force the imaginary resolution we want
g_xres = pixel_xres;
g_yres = pixel_yres;
}
xscale = (float)g_xres / pixel_xres;
yscale = (float)g_yres / pixel_yres;
memset(&input_state, 0, sizeof(input_state));
renderer_inited = false;
first_lost = true;
@ -141,10 +124,18 @@ extern "C" void Java_com_turboviking_libnative_NativeApp_init
std::string app_nice_name;
bool landscape;
net::Init();
g_dpi = dpi;
pixel_xres = xxres;
pixel_yres = yyres;
NativeGetAppInfo(&app_name, &app_nice_name, &landscape);
const char *argv[2] = {app_name.c_str(), 0};
NativeInit(1, argv, user_data_path.c_str(), installID.c_str());
use_native_audio = juseNativeAudio;
if (use_native_audio) {
AndroidAudio_Init(&NativeMix, library_path);
}
@ -164,8 +155,7 @@ extern "C" void Java_com_turboviking_libnative_NativeApp_pause(JNIEnv *, jclass)
}
}
extern "C" void Java_com_turboviking_libnative_NativeApp_shutdown
(JNIEnv *, jclass) {
extern "C" void Java_com_turboviking_libnative_NativeApp_shutdown(JNIEnv *, jclass) {
ILOG("NativeShutdown.");
if (use_native_audio) {
AndroidAudio_Shutdown();
@ -177,26 +167,35 @@ extern "C" void Java_com_turboviking_libnative_NativeApp_shutdown
NativeShutdown();
ILOG("VFSShutdown.");
VFSShutdown();
net::Shutdown();
}
static jmethodID postCommand;
extern "C" void Java_com_turboviking_libnative_NativeRenderer_displayInit(JNIEnv * env, jobject obj) {
if (!renderer_inited) {
ILOG("Calling NativeInitGraphics();");
ILOG("Calling NativeInitGraphics(); dpi = %i", g_dpi);
// We default to 240 dpi and all UI code is written to assume it. (DENSITY_HIGH, like Nexus S).
// Note that we don't compute dp_xscale and dp_yscale until later! This is so that NativeGetAppInfo
// can change the dp resolution if it feels like it.
dp_xres = pixel_xres * 240 / g_dpi;
dp_yres = pixel_yres * 240 / g_dpi;
NativeInitGraphics();
dp_xscale = (float)dp_xres / pixel_xres;
dp_yscale = (float)dp_yres / pixel_yres;
} else {
ILOG("Calling NativeDeviceLost();");
}
renderer_inited = true;
jclass cls = env->GetObjectClass(obj);
postCommand = env->GetMethodID(
cls, "postCommand", "(Ljava/lang/String;Ljava/lang/String;)V");
postCommand = env->GetMethodID(cls, "postCommand", "(Ljava/lang/String;Ljava/lang/String;)V");
ILOG("MethodID: %i", (int)postCommand);
}
extern "C" void Java_com_turboviking_libnative_NativeRenderer_displayResize
(JNIEnv *, jobject clazz, jint w, jint h) {
extern "C" void Java_com_turboviking_libnative_NativeRenderer_displayResize(JNIEnv *, jobject clazz, jint w, jint h) {
ILOG("nativeResize (%i, %i), device lost!", w, h);
if (first_lost) {
first_lost = false;
@ -205,8 +204,7 @@ extern "C" void Java_com_turboviking_libnative_NativeRenderer_displayResize
}
}
extern "C" void Java_com_turboviking_libnative_NativeRenderer_displayRender
(JNIEnv *env, jobject obj) {
extern "C" void Java_com_turboviking_libnative_NativeRenderer_displayRender(JNIEnv *env, jobject obj) {
if (renderer_inited) {
UpdateInputState(&input_state);
NativeUpdate(input_state);
@ -252,15 +250,20 @@ extern "C" void JNICALL Java_com_turboviking_libnative_NativeApp_touch
ELOG("Too many pointers: %i", pointerId);
return; // We ignore 8+ pointers entirely.
}
input_state.mouse_x[pointerId] = (int)(x * xscale);
input_state.mouse_y[pointerId] = (int)(y * yscale);
float scaledX = (int)(x * dp_xscale); // why the (int) cast?
float scaledY = (int)(y * dp_yscale);
input_state.mouse_x[pointerId] = scaledX;
input_state.mouse_y[pointerId] = scaledY;
if (code == 1) {
input_state.mouse_last[pointerId] = input_state.mouse_down[pointerId];
input_state.mouse_down[pointerId] = true;
NativeTouch(pointerId, scaledX, scaledY, 0, TOUCH_DOWN);
} else if (code == 2) {
input_state.mouse_last[pointerId] = input_state.mouse_down[pointerId];
input_state.mouse_down[pointerId] = false;
NativeTouch(pointerId, scaledX, scaledY, 0, TOUCH_UP);
} else {
NativeTouch(pointerId, scaledX, scaledY, 0, TOUCH_MOVE);
}
input_state.mouse_valid = true;
}

View file

@ -13,6 +13,8 @@ struct InputState;
// You must implement this. The first function to get called, just write strings to the two pointers.
// This might get called multiple times in some implementations, you must be able to handle that.
// The detected DP dimensions of the screen are set as dp_xres and dp_yres and you're free to change
// them if you have a fixed-size app that needs to stretch a little to fit.
void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name, bool *landscape);
// For the back button to work right, this should return true on your main or title screen.
@ -28,13 +30,25 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co
void NativeInitGraphics();
// Signals that you need to recreate all buffered OpenGL resources,
// like textures, vbo etc. Main thread.
// like textures, vbo etc. Also, if you have modified dp_xres and dp_yres, you have to
// do it again here. Main thread.
void NativeDeviceLost();
// Called ~sixty times a second, delivers the current input state.
// Main thread.
void NativeUpdate(const InputState &input);
// Delivers touch events "instantly", without waiting for the next frame so that NativeUpdate can deliver.
// Useful for triggering audio events, saving a few ms.
// If you don't care about touch latency, just do a no-op implementation of this.
// time is not yet implemented. finger can be from 0 to 7, inclusive.
enum TouchEvent {
TOUCH_DOWN,
TOUCH_MOVE,
TOUCH_UP,
};
void NativeTouch(int finger, float x, float y, double time, TouchEvent event);
// Called when it's time to render. If the device can keep up, this
// will also be called sixty times per second. Main thread.
void NativeRender();

View file

@ -119,35 +119,34 @@ extern void mixaudio(void *userdata, Uint8 *stream, int len) {
#undef main
#endif
int main(int argc, char *argv[]) {
/* // Xoom resolution. Other common tablet resolutions: 1024x600 , 1366x768
g_xres = 1280;
g_yres = 800;
/* // Xoom/Nexus 7 resolution. Other common tablet resolutions: 1024x600 , 1366x768
dp_xres = 1280;
dp_yres = 800;
*/
std::string app_name;
std::string app_name_nice;
bool landscape;
NativeGetAppInfo(&app_name, &app_name_nice, &landscape);
float zoom = 1.0f;
const char *zoomenv = getenv("ZOOM");
if (zoomenv) {
zoom = atof(zoomenv);
}
if (landscape) {
bool landscape;
NativeGetAppInfo(&app_name, &app_name_nice, &landscape);
if (landscape) {
pixel_xres = 800 * zoom;
pixel_yres = 480 * zoom;
} else {
// PC development hack
pixel_xres = 1580 * zoom;
pixel_yres = 1000 * zoom;
// PC development hack for more space
//pixel_xres = 1580 * zoom;
//pixel_yres = 1000 * zoom;
pixel_xres = 480 * zoom;
pixel_yres = 800 * zoom;
}
float density = 1.0f;
g_xres = (float)pixel_xres * density / zoom;
g_yres = (float)pixel_yres * density / zoom;
printf("Pixels: %i x %i\n", pixel_xres, pixel_yres);
printf("Virtual pixels: %i x %i\n", g_xres, g_yres);
net::Init();
@ -185,27 +184,35 @@ int main(int argc, char *argv[]) {
return 1;
}
#ifdef _MSC_VER
// VFSRegister("temp/", new DirectoryAssetReader("E:\\Temp\\"));
TCHAR path[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path);
PathAppend(path, (app_name + "\\").c_str());
#else
// Mac - what about linux? Also, ugly hardcoding.
// Mac / Linux
const char *path = getenv("HOME");
if (!path) {
struct passwd* pwd = getpwuid(getuid());
if (pwd)
path = pwd->pw_dir;
}
#endif
NativeInit(argc, (const char **)argv, path, "BADCOFFEE");
float density = 1.0f;
dp_xres = (float)pixel_xres * density / zoom;
dp_yres = (float)pixel_yres * density / zoom;
NativeInitGraphics();
float dp_xscale = (float)dp_xres / pixel_xres;
float dp_yscale = (float)dp_yres / pixel_yres;
printf("Pixels: %i x %i\n", pixel_xres, pixel_yres);
printf("Virtual pixels: %i x %i\n", dp_xres, dp_yres);
SDL_AudioSpec fmt;
fmt.freq = 44100;
fmt.format = AUDIO_S16;
@ -225,44 +232,51 @@ int main(int argc, char *argv[]) {
InputState input_state;
int framecount = 0;
bool nextFrameMD = 0;
float t = 0;
while (true) {
SDL_Event event;
input_state.accelerometer_valid = false;
input_state.mouse_valid = true;
int done = 0;
int quitRequested = 0;
// input_state.mouse_down[1] = nextFrameMD;
while (SDL_PollEvent(&event)) {
float mx = event.motion.x * dp_xscale;
float my = event.motion.y * dp_yscale;
if (event.type == SDL_QUIT) {
done = 1;
quitRequested = 1;
} else if (event.type == SDL_KEYDOWN) {
if (event.key.keysym.sym == SDLK_ESCAPE) {
done = 1;
quitRequested = 1;
}
} else if (event.type == SDL_MOUSEMOTION) {
input_state.mouse_x[0] = event.motion.x * density / zoom;
input_state.mouse_y[0] = event.motion.y * density / zoom;
input_state.mouse_x[0] = mx;
input_state.mouse_y[0] = my;
NativeTouch(0, mx, my, 0, TOUCH_MOVE);
} else if (event.type == SDL_MOUSEBUTTONDOWN) {
if (event.button.button == SDL_BUTTON_LEFT) {
//input_state.mouse_buttons_down = 1;
input_state.mouse_down[0] = true;
nextFrameMD = true;
NativeTouch(0, mx, my, 0, TOUCH_DOWN);
}
} else if (event.type == SDL_MOUSEBUTTONUP) {
if (event.button.button == SDL_BUTTON_LEFT) {
input_state.mouse_down[0] = false;
nextFrameMD = false;
//input_state.mouse_buttons_up = 1;
NativeTouch(0, mx, my, 0, TOUCH_UP);
}
}
}
if (done)
if (quitRequested)
break;
input_state.mouse_last[0] = input_state.mouse_down[0];
uint8 *keys = (uint8 *)SDL_GetKeyState(NULL);
const uint8 *keys = (const uint8 *)SDL_GetKeyState(NULL);
if (keys[SDLK_ESCAPE])
break;
SimulateGamepad(keys, &input_state);
@ -270,14 +284,13 @@ int main(int argc, char *argv[]) {
NativeUpdate(input_state);
NativeRender();
if (framecount % 60 == 0) {
// glsl_refresh(); // auto-reloads modified GLSL shaders once per second.
// glsl_refresh(); // auto-reloads modified GLSL shaders once per second.
}
SDL_GL_SwapBuffers();
// Simple framerate limiting
static float t=0;
while (time_now() < t+1.0f/60.0f) {
while (time_now() < t + 1.0f/60.0f) {
sleep_ms(0);
time_update();
}
@ -293,5 +306,6 @@ int main(int argc, char *argv[]) {
NativeShutdown();
SDL_CloseAudio();
SDL_Quit();
net::Shutdown();
return 0;
}

View file

@ -1,7 +1,7 @@
#include "base/display.h"
int g_xres;
int g_yres;
int dp_xres;
int dp_yres;
int pixel_xres;
int pixel_yres;

View file

@ -3,8 +3,8 @@
// This is meant to be a framework for handling DPI scaling etc.
// For now, it just consists of these two ugly globals.
extern int g_xres;
extern int g_yres;
extern int dp_xres;
extern int dp_yres;
extern int pixel_xres;
extern int pixel_yres;

View file

@ -359,7 +359,7 @@ void DrawBuffer::EnableBlend(bool enable) {
void DrawBuffer::SetClipRect(float x, float y, float w, float h)
{
// Sigh, OpenGL is upside down.
glScissor(x, g_yres - y, w, h);
glScissor(x, dp_yres - y, w, h);
glEnable(GL_SCISSOR_TEST);
}

View file

@ -46,6 +46,7 @@ bool Connection::Resolve(const char *host, int port) {
CHECK_GE(tmpres, 0); // << "inet_pton failed";
CHECK_NE(0, tmpres); // << ip << " not a valid IP address";
remote_.sin_port = htons(port);
free((void *)ip);
return true;
}
@ -53,7 +54,6 @@ void Connection::Connect() {
CHECK_GE(port_, 0);
sock_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
CHECK_GE(sock_, 0);
//VLOG(1) << "Connecting to " << host_ << ":" << port_;
// poll once per second.. should find a way to do this blocking.
int retval = -1;

View file

@ -16,7 +16,6 @@
namespace net {
void Init()
{
#ifdef _WIN32
@ -25,6 +24,13 @@ void Init()
#endif
}
void Shutdown()
{
#ifdef _WIN32
WSACleanup();
#endif
}
char *DNSResolve(const char *host)
{
struct hostent *hent;

View file

@ -3,8 +3,9 @@
namespace net {
// Required on Win32
// Strictly only required on Win32, but all platforms should call it.
void Init();
void Shutdown();
// use free() to free the returned string.
char *DNSResolve(const char *host);