diff --git a/Projects/Android/jni/Quake2VR/VrInputDefault.c b/Projects/Android/jni/Quake2VR/VrInputDefault.c index 035a9ad..903927c 100644 --- a/Projects/Android/jni/Quake2VR/VrInputDefault.c +++ b/Projects/Android/jni/Quake2VR/VrInputDefault.c @@ -21,6 +21,12 @@ Authors : Simon Brown extern cvar_t *cl_forwardspeed; cvar_t *sv_cheats; extern cvar_t *vr_weapon_stabilised; +qboolean draw_wep_wheel; +vec3_t initialAngles; +vec3_t currentAngles; +vec2_t relativeAngles; +vec2_t polarCursor; +int segment; @@ -41,6 +47,10 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, uint32_t primaryButtonsOld; uint32_t secondaryButtonsNew; uint32_t secondaryButtonsOld; + uint32_t primaryTouchesNew; + uint32_t primaryTouchesOld; + uint32_t secondaryTouchesNew; + uint32_t secondaryTouchesOld; int primaryButton1; int primaryButton2; int secondaryButton1; @@ -58,6 +68,12 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, secondaryButtonsNew = pDominantTrackedRemoteNew->Buttons; secondaryButtonsOld = pDominantTrackedRemoteOld->Buttons; + primaryTouchesNew = pDominantTrackedRemoteNew->Touches; + primaryTouchesOld = pDominantTrackedRemoteOld->Touches; + + secondaryTouchesNew = pOffTrackedRemoteNew->Touches; + secondaryTouchesOld = pOffTrackedRemoteOld->Touches; + primaryButton1 = offButton1; primaryButton2 = offButton2; secondaryButton1 = domButton1; @@ -75,6 +91,12 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, secondaryButtonsNew = pOffTrackedRemoteNew->Buttons; secondaryButtonsOld = pOffTrackedRemoteOld->Buttons; + primaryTouchesNew = pDominantTrackedRemoteNew->Touches; + primaryTouchesOld = pDominantTrackedRemoteOld->Touches; + + secondaryTouchesNew = pOffTrackedRemoteNew->Touches; + secondaryTouchesOld = pOffTrackedRemoteOld->Touches; + primaryButton1 = domButton1; primaryButton2 = domButton2; secondaryButton1 = offButton1; @@ -201,6 +223,72 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, sendButtonActionSimple("inven"); inventoryManagementMode = (secondaryButtonsNew & secondaryButton2) > 0; } + + if ((primaryTouchesNew & ovrTouch_ThumbRest) != + (primaryTouchesOld & ovrTouch_ThumbRest)) { + sendButtonActionSimple("inven"); // send the "inven" command to force cl.inventory to be populated + } + + // weapon selection wheel + { + static qboolean touching = false; + static qboolean runTouchLogic = false; + static int t_rel_t; + + if ((primaryTouchesNew & ovrTouch_ThumbRest)) { + if (!touching) { + draw_wep_wheel = true; + QuatToYawPitchRoll(pDominantTracking->HeadPose.Pose.Orientation, 0.0f, + initialAngles); + VectorCopy(initialAngles, relativeAngles); + touching = true; + } else { + QuatToYawPitchRoll(pDominantTracking->HeadPose.Pose.Orientation, 0.0f, + currentAngles); + relativeAngles[0] = initialAngles[1] - + currentAngles[1]; // relative x -> pitch | Inverted to make right = positive + relativeAngles[1] = currentAngles[0] - + initialAngles[0]; // relative y -> yaw | to match display coordinates, down = positive + polarCursor[0] = sqrtf( + powf(relativeAngles[0], 2.0f) + powf(relativeAngles[1], 2.0f)); // r + if (polarCursor[0] > 15) + polarCursor[0] = 15; // to keep it within the ring + polarCursor[1] = atan2f(relativeAngles[1], relativeAngles[0]); // theta + segment = (int) (((polarCursor[1] + (M_PI / 11)) + (2.5 * M_PI)) * + (11 / (2 * M_PI))) % + 11; // Top segment index = 0, clockwise up to 10 + + /*float th = M_PI/-2; + int r = 160; + float factor = M_PI * 2/11; + for(int i = 0; i < 11; i++){ + int x, y; + x = r * cosf(th + (i * factor)); + y = r * sinf(th + (i * factor)); + ALOGV(" segment %i: x: %i y=%i", i, x, y); + }*/ // this snippet generated precalculated coordinates for each weapon icon, relative to the ring center + // I'll leave it here in case those values need to be calculated again + + } + } else { + if(touching){ + touching = false; + runTouchLogic = true; + t_rel_t = Sys_Milliseconds(); + if (polarCursor[0] > 8) { + char useCom[50]; + sprintf(useCom, "use %s", weaponIcons[segment].command); + sendButtonActionSimple(useCom); + } + } + // give it time for the "inven" commmand to be sent, + // preventing the "invisible" inventory window to be shown for a little bit + if(runTouchLogic && Sys_Milliseconds() - t_rel_t > 100) { + draw_wep_wheel = false; + runTouchLogic = false; + } + } + } } float controllerYawHeading = 0.0f; diff --git a/Projects/Android/jni/quake2/src/client/cl_inventory.c b/Projects/Android/jni/quake2/src/client/cl_inventory.c index cbfbe14..d5573ba 100644 --- a/Projects/Android/jni/quake2/src/client/cl_inventory.c +++ b/Projects/Android/jni/quake2/src/client/cl_inventory.c @@ -26,6 +26,8 @@ #include "header/client.h" +extern qboolean draw_wep_wheel; + void CL_ParseInventory(void) { @@ -62,103 +64,103 @@ SetStringHighBit(char *s) void CL_DrawInventory(float separation) { - int i, j; - int num, selected_num, item; - int index[MAX_ITEMS]; - char string[1024]; - int x, y; - char binding[1024]; - const char *bind; - int selected; - int top; + if(!draw_wep_wheel) { // do not draw if weapon wheel is being drawn + Com_Printf("qiqiqiqi inventory drawn at %i", Sys_Milliseconds()); + int i, j; + int num, selected_num, item; + int index[MAX_ITEMS]; + char string[1024]; + int x, y; + char binding[1024]; + const char *bind; + int selected; + int top; - selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM]; + selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM]; - int offset_stereo= (separation>0) ? -25 : 25; - num = 0; - selected_num = 0; + int offset_stereo = (separation > 0) ? -25 : 25; + num = 0; + selected_num = 0; - float scale = SCR_GetHUDScale(); + float scale = SCR_GetHUDScale(); - for (i = 0; i < MAX_ITEMS; i++) - { - if (i == selected) - { - selected_num = num; - } + for (i = 0; i < MAX_ITEMS; i++) + { + if (i == selected) { + selected_num = num; + } - if (cl.inventory[i]) - { - index[num] = i; - num++; - } - } + if (cl.inventory[i]) { + index[num] = i; + num++; + } + } - /* determine scroll point */ - top = selected_num - DISPLAY_ITEMS / 2; + /* determine scroll point */ + top = selected_num - DISPLAY_ITEMS / 2; - if (num - top < DISPLAY_ITEMS) - { - top = num - DISPLAY_ITEMS; - } + if (num - top < DISPLAY_ITEMS) + { + top = num - DISPLAY_ITEMS; + } - if (top < 0) - { - top = 0; - } + if (top < 0) + { + top = 0; + } - x = (viddef.width - scale*256) / 2; - y = viddef.height/2; + x = (viddef.width - scale * 256) / 2; + y = viddef.height / 2; - /* repaint everything next frame */ - SCR_DirtyScreen(); + /* repaint everything next frame */ + SCR_DirtyScreen(); - Draw_PicScaled(x+offset_stereo, y + scale*8, "inventory", scale); + Draw_PicScaled(x + offset_stereo, y + scale * 8, "inventory", scale); - y += scale*24; - x += scale*24; + y += scale * 24; + x += scale * 24; - //Inv_DrawStringScaled(x, y, "hotkey ### item", scale); - //Inv_DrawStringScaled(x, y + scale*8, "------ --- ----", scale); + //Inv_DrawStringScaled(x, y, "hotkey ### item", scale); + //Inv_DrawStringScaled(x, y + scale*8, "------ --- ----", scale); - y += scale*16; + y += scale * 16; - for (i = top; i < num && i < top + DISPLAY_ITEMS; i++) - { - item = index[i]; - /* search for a binding */ - Com_sprintf(binding, sizeof(binding), "use %s", - cl.configstrings[CS_ITEMS + item]); - bind = ""; + for (i = top; i < num && i < top + DISPLAY_ITEMS; i++) + { + item = index[i]; + /* search for a binding */ + Com_sprintf(binding, sizeof(binding), "use %s", + cl.configstrings[CS_ITEMS + item]); + bind = ""; - /*for (j = 0; j < 256; j++) - { - if (keybindings[j] && !Q_stricmp(keybindings[j], binding)) - { - bind = Key_KeynumToString(j); - break; - } - }*/ + /*for (j = 0; j < 256; j++) + { + if (keybindings[j] && !Q_stricmp(keybindings[j], binding)) + { + bind = Key_KeynumToString(j); + break; + } + }*/ - Com_sprintf(string, sizeof(string), "%6s %3i %s", bind, - cl.inventory[item], cl.configstrings[CS_ITEMS + item]); + Com_sprintf(string, sizeof(string), "%6s %3i %s", bind, + cl.inventory[item], cl.configstrings[CS_ITEMS + item]); - if (item != selected) - { - SetStringHighBit(string); - } - else - { - /* draw a blinky cursor by the selected item */ - if ((int)(cls.realtime * 10) & 1) - { - Draw_CharScaled(x + offset_stereo - scale*8, y, 15, scale); - } - } + if (item != selected) + { + SetStringHighBit(string); + } + else + { + /* draw a blinky cursor by the selected item */ + if ((int) (cls.realtime * 10) & 1) { + Draw_CharScaled(x + offset_stereo - scale * 8, y, 15, scale); + } + } - Inv_DrawStringScaled(x+offset_stereo, y, string, scale); + Inv_DrawStringScaled(x + offset_stereo, y, string, scale); - y += scale*8; - } + y += scale * 8; + } + } } diff --git a/Projects/Android/jni/quake2/src/client/cl_screen.c b/Projects/Android/jni/quake2/src/client/cl_screen.c index 84ccb12..d0a1868 100644 --- a/Projects/Android/jni/quake2/src/client/cl_screen.c +++ b/Projects/Android/jni/quake2/src/client/cl_screen.c @@ -72,6 +72,108 @@ extern cvar_t *crosshair_scale; void SCR_TimeRefresh_f(void); void SCR_Loading_f(void); +wheel_icon_t weaponIcons[11] = { + { + "blaster", + 7, + "Blaster", + NULL, + 0, + 0, + -160 + }, + { + "shotgun", + 8, + "Shotgun", + "shells", + 18, + 86, + -134 + }, + { + "sshotgun", + 9, + "Super Shotgun", + "shells", + 18, + 145, + -66 + }, + { + "machinegun", + 10, + "Machinegun", + "bullets", + 19, + 158, + 22 + }, + { + "chaingun", + 11, + "Chaingun", + "bullets", + 19, + 120, + 104 + }, + { + "grenades", + 12, + "Grenades", + "grenades", + 12, + 45, + 153 + }, + { + "glauncher", + 13, + "Grenade Launcher", + "grenades", + 12, + -45, + 153 + }, + { + "rlauncher", + 14, + "Rocket Launcher", + "rockets", + 21, + -120, + 104 + }, + { + "hyperblaster", + 15, + "HyperBlaster", + "cells", + 20, + -158, + 22 + }, + { + "railgun", + 16, + "Railgun", + "slugs", + 22, + -145, + -66 + }, + { + "bfg", + 17, + "BFG10K", + "cells", + 20, + -86, + -134 + } +}; + /* * A new packet was just parsed */ @@ -516,6 +618,91 @@ void SCR_DrawVignette (void) } } +extern qboolean draw_wep_wheel; +extern vec2_t polarCursor; +extern int segment; +static float cursorFactor = 200/15; // 200 is the radius of the ring image + // 15 is the same radius in VR scale + +void +DrawNumberCenteredImageScaled(int x, int y, char* num, float scale) +{ + int len = strlen(num); + int width = 8; // half of img width + int height = 12; // half of img height + for(int i = 0; i < len; i++){ + char image[7]; + sprintf(image, "anum_%c", num[i]); + float offset = width * ((i * 2) - (len)); + Draw_PicScaled(x + offset, y - (height * scale), image, + scale); + } +} + +void +SCR_DrawWeaponWheel (float separation) +{ + if(draw_wep_wheel) + { + int offset_stereo = (separation>0) ? -25 : 25; + int picw, pich; + int curw, curh; + int vidwc = (viddef.width/2); + int vidhc = (viddef.height/2); + Draw_GetPicSize(&picw, &pich,"/ring.png"); + Draw_PicScaled((vidwc - (picw/2)) + offset_stereo, (vidhc - (pich/2)), "/ring.png", 1.0f); + Draw_GetPicSize(&curw, &curh,"/cursor.png"); + Draw_PicScaled((vidwc - (curw/2)) + ((polarCursor[0] * cosf(polarCursor[1])) * cursorFactor) + offset_stereo, + (vidwc - (curh/2)) + ((polarCursor[0] * sinf(polarCursor[1])) * cursorFactor), + "/cursor.png", 1.0f); + + for(int i = 0; i < 11; i++) + { + if(cl.inventory[weaponIcons[i].index]) + { // if weapon is available in inventory + char iconName[35]; + char ammoName[30]; + char ammoAmount[4]; + float iconFactor; + float ammoFactor = 4.0f; + int iconWidth = 12; // actually half of icon size. For centering purposes + if (i == segment && polarCursor[0] > 8) + { // if cursor is inside the segment corresponding to the weapon + iconFactor = 2.5f; + sprintf(iconName, "/wheel/w_%s_selected.png", weaponIcons[i].name); + sprintf(ammoName, "/wheel/a_%s.png", weaponIcons[i].ammo); + DrawStringScaled(vidwc + offset_stereo - (strlen(weaponIcons[i].command) * 4), + vidhc - 100, + weaponIcons[i].command, 1.0f); // Weapon name + if(weaponIcons[i].ammo_i > 0) + { + sprintf(ammoAmount, "%i", cl.inventory[weaponIcons[i].ammo_i]); + DrawNumberCenteredImageScaled(vidwc + offset_stereo, vidhc + 100, + ammoAmount, + 1.0f); // ammo amount in image numbers + } + Draw_PicScaled(vidwc - (iconWidth * ammoFactor) + offset_stereo, // ammo icon for the weapon + vidhc - (iconWidth * ammoFactor), ammoName, + ammoFactor); + Draw_PicScaled(vidwc + weaponIcons[i].x - (iconWidth * iconFactor) + + (offset_stereo * 1.3f), + vidhc + weaponIcons[i].y - (iconWidth * iconFactor), iconName, + iconFactor); + } + else + { + iconFactor = 1.5f; + sprintf(iconName, "/wheel/w_%s.png", weaponIcons[i].name); + Draw_PicScaled(vidwc + weaponIcons[i].x - (iconWidth * iconFactor) + (offset_stereo), + vidhc + weaponIcons[i].y - (iconWidth * iconFactor), iconName, + iconFactor); + } + } + } + + } +} + void SCR_DrawLoading(void) { @@ -1647,6 +1834,8 @@ void SCR_UpdateForEye (int eye) CL_DrawInventory(separation); } + SCR_DrawWeaponWheel(separation); + SCR_DrawNet(); SCR_CheckDrawCenterString(); diff --git a/Projects/Android/jni/quake2/src/client/header/client.h b/Projects/Android/jni/quake2/src/client/header/client.h index 95592e4..c851f6b 100644 --- a/Projects/Android/jni/quake2/src/client/header/client.h +++ b/Projects/Android/jni/quake2/src/client/header/client.h @@ -319,6 +319,19 @@ extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; extern netadr_t net_from; extern sizebuf_t net_message; +typedef struct +{ + const char* name; // segment for matching icon file + const int index; // weapon index in inventory + const char* command; // command triggered when icon is selected. Also display name + const char* ammo; // type of ammo used by this weapon + const int ammo_i; // index of ammo amount in inventory + const int x; // h offset from center of selection wheel + const int y; // v offset from center of selection wheel +} wheel_icon_t; + +extern wheel_icon_t weaponIcons[]; + void DrawString (int x, int y, char *s); void DrawStringScaled(int x, int y, char *s, float factor); void DrawAltString (int x, int y, char *s); /* toggle high bit */