+ qglGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_2d);
+ if (vid.support.ext_texture_filter_anisotropic)
+ qglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint*)&vid.max_anisotropy);
+ if (vid.support.arb_texture_cube_map)
+ qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, (GLint*)&vid.maxtexturesize_cubemap);
+ if (vid.support.ext_texture_3d)
+ qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_3d);
+
+ // verify that 3d textures are really supported
+ if (vid.support.ext_texture_3d && vid.maxtexturesize_3d < 32)
+ {
+ vid.support.ext_texture_3d = false;
+ Con_Printf("GL_EXT_texture3D reported bogus GL_MAX_3D_TEXTURE_SIZE, disabled\n");
+ }
+
+ vid.texunits = vid.teximageunits = vid.texarrayunits = 1;
+ if (vid.support.arb_multitexture)
+ qglGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&vid.texunits);
+ if (vid_gl20.integer && vid.support.gl20shaders)
+ {
+ qglGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&vid.texunits);
+ qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (int *)&vid.teximageunits);CHECKGLERROR
+ qglGetIntegerv(GL_MAX_TEXTURE_COORDS, (int *)&vid.texarrayunits);CHECKGLERROR
+ vid.texunits = bound(4, vid.texunits, MAX_TEXTUREUNITS);
+ vid.teximageunits = bound(16, vid.teximageunits, MAX_TEXTUREUNITS);
+ vid.texarrayunits = bound(8, vid.texarrayunits, MAX_TEXTUREUNITS);
+ Con_DPrintf("Using GL2.0 rendering path - %i texture matrix, %i texture images, %i texcoords%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.support.ext_framebuffer_object ? ", shadowmapping supported" : "");
+ vid.renderpath = RENDERPATH_GL20;
+ vid.sRGBcapable2D = false;
+ vid.sRGBcapable3D = true;
+ vid.useinterleavedarrays = false;
+ }
+ else if (vid.support.arb_texture_env_combine && vid.texunits >= 2 && vid_gl13.integer)
+ {
+ qglGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&vid.texunits);
+ vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS);
+ vid.teximageunits = vid.texunits;
+ vid.texarrayunits = vid.texunits;
+ Con_DPrintf("Using GL1.3 rendering path - %i texture units, single pass rendering\n", vid.texunits);
+ vid.renderpath = RENDERPATH_GL13;
+ vid.sRGBcapable2D = false;
+ vid.sRGBcapable3D = false;
+ vid.useinterleavedarrays = false;
+ }
+ else
+ {
+ vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS);
+ vid.teximageunits = vid.texunits;
+ vid.texarrayunits = vid.texunits;
+ Con_DPrintf("Using GL1.1 rendering path - %i texture units, two pass rendering\n", vid.texunits);
+ vid.renderpath = RENDERPATH_GL11;
+ vid.sRGBcapable2D = false;
+ vid.sRGBcapable3D = false;
+ vid.useinterleavedarrays = false;
+ }
+
+ // VorteX: set other info (maybe place them in VID_InitMode?)
+ Cvar_SetQuick(&gl_info_vendor, gl_vendor);
+ Cvar_SetQuick(&gl_info_renderer, gl_renderer);
+ Cvar_SetQuick(&gl_info_version, gl_version);
+ Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : "");
+ Cvar_SetQuick(&gl_info_driver, gl_driver);
+}
+
+float VID_JoyState_GetAxis(const vid_joystate_t *joystate, int axis, float sensitivity, float deadzone)
+{
+ float value;
+ value = (axis >= 0 && axis < MAXJOYAXIS) ? joystate->axis[axis] : 0.0f;
+ value = value > deadzone ? (value - deadzone) : (value < -deadzone ? (value + deadzone) : 0.0f);
+ value *= deadzone > 0 ? (1.0f / (1.0f - deadzone)) : 1.0f;
+ value = bound(-1, value, 1);
+ return value * sensitivity;
+}
+
+qboolean VID_JoyBlockEmulatedKeys(int keycode)
+{
+ int j;
+ vid_joystate_t joystate;
+
+ if (!joy_axiskeyevents.integer)
+ return false;
+ if (vid_joystate.is360)
+ return false;
+ if (keycode != K_UPARROW && keycode != K_DOWNARROW && keycode != K_RIGHTARROW && keycode != K_LEFTARROW)
+ return false;
+
+ // block system-generated key events for arrow keys if we're emulating the arrow keys ourselves
+ VID_BuildJoyState(&joystate);
+ for (j = 32;j < 36;j++)
+ if (vid_joystate.button[j] || joystate.button[j])
+ return true;
+
+ return false;
+}
+
+void VID_Shared_BuildJoyState_Begin(vid_joystate_t *joystate)
+{
+#ifdef WIN32
+ xinput_state_t xinputstate;
+#endif
+ memset(joystate, 0, sizeof(*joystate));
+#ifdef WIN32
+ if (vid_xinputindex >= 0 && qXInputGetState && qXInputGetState(vid_xinputindex, &xinputstate) == S_OK)
+ {
+ joystate->is360 = true;
+ joystate->button[ 0] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0;
+ joystate->button[ 1] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0;
+ joystate->button[ 2] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0;
+ joystate->button[ 3] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0;
+ joystate->button[ 4] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0;
+ joystate->button[ 5] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0;
+ joystate->button[ 6] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0;
+ joystate->button[ 7] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0;
+ joystate->button[ 8] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0;
+ joystate->button[ 9] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0;
+ joystate->button[10] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0;
+ joystate->button[11] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0;
+ joystate->button[12] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0;
+ joystate->button[13] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0;
+ joystate->button[14] = xinputstate.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
+ joystate->button[15] = xinputstate.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
+ joystate->button[16] = xinputstate.Gamepad.sThumbLY < -16384;
+ joystate->button[17] = xinputstate.Gamepad.sThumbLY > 16384;
+ joystate->button[18] = xinputstate.Gamepad.sThumbLX < -16384;
+ joystate->button[19] = xinputstate.Gamepad.sThumbLX > 16384;
+ joystate->button[20] = xinputstate.Gamepad.sThumbRY < -16384;
+ joystate->button[21] = xinputstate.Gamepad.sThumbRY > 16384;
+ joystate->button[22] = xinputstate.Gamepad.sThumbRX < -16384;
+ joystate->button[23] = xinputstate.Gamepad.sThumbRX > 16384;
+ joystate->axis[ 4] = xinputstate.Gamepad.bLeftTrigger * (1.0f / 255.0f);
+ joystate->axis[ 5] = xinputstate.Gamepad.bRightTrigger * (1.0f / 255.0f);
+ joystate->axis[ 0] = xinputstate.Gamepad.sThumbLX * (1.0f / 32767.0f);
+ joystate->axis[ 1] = xinputstate.Gamepad.sThumbLY * (1.0f / 32767.0f);
+ joystate->axis[ 2] = xinputstate.Gamepad.sThumbRX * (1.0f / 32767.0f);
+ joystate->axis[ 3] = xinputstate.Gamepad.sThumbRY * (1.0f / 32767.0f);
+ }
+#endif
+}
+
+void VID_Shared_BuildJoyState_Finish(vid_joystate_t *joystate)
+{
+ float f, r;
+ if (joystate->is360)
+ return;
+ // emulate key events for thumbstick
+ f = VID_JoyState_GetAxis(joystate, joy_axisforward.integer, 1, joy_axiskeyevents_deadzone.value) * joy_sensitivityforward.value;
+ r = VID_JoyState_GetAxis(joystate, joy_axisside.integer , 1, joy_axiskeyevents_deadzone.value) * joy_sensitivityside.value;
+#if MAXJOYBUTTON != 36
+#error this code must be updated if MAXJOYBUTTON changes!
+#endif
+ joystate->button[32] = f > 0.0f;
+ joystate->button[33] = f < 0.0f;
+ joystate->button[34] = r > 0.0f;
+ joystate->button[35] = r < 0.0f;
+}
+
+void VID_KeyEventForButton(qboolean oldbutton, qboolean newbutton, int key, double *timer)
+{
+ if (oldbutton)
+ {
+ if (newbutton)
+ {
+ if (realtime >= *timer)
+ {
+ Key_Event(key, 0, true);
+ *timer = realtime + 0.1;
+ }
+ }
+ else
+ {
+ Key_Event(key, 0, false);
+ *timer = 0;
+ }
+ }
+ else
+ {
+ if (newbutton)
+ {
+ Key_Event(key, 0, true);
+ *timer = realtime + 0.5;
+ }
+ }
+}
+
+#if MAXJOYBUTTON != 36
+#error this code must be updated if MAXJOYBUTTON changes!
+#endif
+static int joybuttonkey[MAXJOYBUTTON][2] =
+{
+ {K_JOY1, K_ENTER}, {K_JOY2, K_ESCAPE}, {K_JOY3, 0}, {K_JOY4, 0}, {K_JOY5, 0}, {K_JOY6, 0}, {K_JOY7, 0}, {K_JOY8, 0}, {K_JOY9, 0}, {K_JOY10, 0}, {K_JOY11, 0}, {K_JOY12, 0}, {K_JOY13, 0}, {K_JOY14, 0}, {K_JOY15, 0}, {K_JOY16, 0},
+ {K_AUX1, 0}, {K_AUX2, 0}, {K_AUX3, 0}, {K_AUX4, 0}, {K_AUX5, 0}, {K_AUX6, 0}, {K_AUX7, 0}, {K_AUX8, 0}, {K_AUX9, 0}, {K_AUX10, 0}, {K_AUX11, 0}, {K_AUX12, 0}, {K_AUX13, 0}, {K_AUX14, 0}, {K_AUX15, 0}, {K_AUX16, 0},
+ {K_JOY_UP, K_UPARROW}, {K_JOY_DOWN, K_DOWNARROW}, {K_JOY_RIGHT, K_RIGHTARROW}, {K_JOY_LEFT, K_LEFTARROW},
+};
+
+static int joybuttonkey360[][2] =
+{
+ {K_X360_DPAD_UP, K_UPARROW},
+ {K_X360_DPAD_DOWN, K_DOWNARROW},
+ {K_X360_DPAD_LEFT, K_LEFTARROW},
+ {K_X360_DPAD_RIGHT, K_RIGHTARROW},
+ {K_X360_START, K_ESCAPE},
+ {K_X360_BACK, K_ESCAPE},
+ {K_X360_LEFT_THUMB, 0},
+ {K_X360_RIGHT_THUMB, 0},
+ {K_X360_LEFT_SHOULDER, 0},
+ {K_X360_RIGHT_SHOULDER, 0},
+ {K_X360_A, K_ENTER},
+ {K_X360_B, K_ESCAPE},
+ {K_X360_X, 0},
+ {K_X360_Y, 0},
+ {K_X360_LEFT_TRIGGER, 0},
+ {K_X360_RIGHT_TRIGGER, 0},
+ {K_X360_LEFT_THUMB_DOWN, K_DOWNARROW},
+ {K_X360_LEFT_THUMB_UP, K_UPARROW},
+ {K_X360_LEFT_THUMB_LEFT, K_LEFTARROW},
+ {K_X360_LEFT_THUMB_RIGHT, K_RIGHTARROW},
+ {K_X360_RIGHT_THUMB_DOWN, 0},
+ {K_X360_RIGHT_THUMB_UP, 0},
+ {K_X360_RIGHT_THUMB_LEFT, 0},
+ {K_X360_RIGHT_THUMB_RIGHT, 0},
+};
+
+double vid_joybuttontimer[MAXJOYBUTTON];
+void VID_ApplyJoyState(vid_joystate_t *joystate)
+{
+ int j;
+ int c = joy_axiskeyevents.integer != 0;
+ if (joystate->is360)
+ {
+#if 0
+ // keystrokes (chatpad)
+ // DOES NOT WORK - no driver support in xinput1_3.dll :(
+ xinput_keystroke_t keystroke;
+ while (qXInputGetKeystroke && qXInputGetKeystroke(XUSER_INDEX_ANY, 0, &keystroke) == S_OK)
+ Con_Printf("XInput KeyStroke: VirtualKey %i, Unicode %i, Flags %x, UserIndex %i, HidCode %i\n", keystroke.VirtualKey, keystroke.Unicode, keystroke.Flags, keystroke.UserIndex, keystroke.HidCode);
+#endif
+
+ // emit key events for buttons
+ for (j = 0;j < (int)(sizeof(joybuttonkey360)/sizeof(joybuttonkey360[0]));j++)
+ VID_KeyEventForButton(vid_joystate.button[j] != 0, joystate->button[j] != 0, joybuttonkey360[j][c], &vid_joybuttontimer[j]);
+
+ // axes
+ cl.cmd.forwardmove += VID_JoyState_GetAxis(joystate, joy_x360_axisforward.integer, joy_x360_sensitivityforward.value, joy_x360_deadzoneforward.value) * cl_forwardspeed.value;
+ cl.cmd.sidemove += VID_JoyState_GetAxis(joystate, joy_x360_axisside.integer, joy_x360_sensitivityside.value, joy_x360_deadzoneside.value) * cl_sidespeed.value;
+ cl.cmd.upmove += VID_JoyState_GetAxis(joystate, joy_x360_axisup.integer, joy_x360_sensitivityup.value, joy_x360_deadzoneup.value) * cl_upspeed.value;
+ cl.viewangles[0] += VID_JoyState_GetAxis(joystate, joy_x360_axispitch.integer, joy_x360_sensitivitypitch.value, joy_x360_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
+ cl.viewangles[1] += VID_JoyState_GetAxis(joystate, joy_x360_axisyaw.integer, joy_x360_sensitivityyaw.value, joy_x360_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
+ //cl.viewangles[2] += VID_JoyState_GetAxis(joystate, joy_x360_axisroll.integer, joy_x360_sensitivityroll.value, joy_x360_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
+ }
+ else
+ {
+ // emit key events for buttons
+ for (j = 0;j < MAXJOYBUTTON;j++)
+ VID_KeyEventForButton(vid_joystate.button[j] != 0, joystate->button[j] != 0, joybuttonkey[j][c], &vid_joybuttontimer[j]);
+
+ // axes
+ cl.cmd.forwardmove += VID_JoyState_GetAxis(joystate, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value;
+ cl.cmd.sidemove += VID_JoyState_GetAxis(joystate, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value;
+ cl.cmd.upmove += VID_JoyState_GetAxis(joystate, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value;
+ cl.viewangles[0] += VID_JoyState_GetAxis(joystate, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
+ cl.viewangles[1] += VID_JoyState_GetAxis(joystate, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
+ //cl.viewangles[2] += VID_JoyState_GetAxis(joystate, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
+ }
+
+ vid_joystate = *joystate;
+}
+
+int VID_Shared_SetJoystick(int index)
+{
+#ifdef WIN32
+ int i;
+ int xinputcount = 0;
+ int xinputindex = -1;
+ int xinputavailable = 0;
+ xinput_state_t state;
+ // detect available XInput controllers
+ for (i = 0;i < 4;i++)
+ {
+ if (qXInputGetState && qXInputGetState(i, &state) == S_OK)
+ {
+ xinputavailable |= 1<<i;
+ if (index == xinputcount)
+ xinputindex = i;
+ xinputcount++;
+ }
+ }
+ if (joy_xinputavailable.integer != xinputavailable)
+ Cvar_SetValueQuick(&joy_xinputavailable, xinputavailable);
+ if (vid_xinputindex != xinputindex)
+ {
+ vid_xinputindex = xinputindex;
+ if (xinputindex >= 0)
+ Con_Printf("Joystick %i opened (XInput Device %i)\n", index, xinputindex);
+ }
+ return xinputcount;
+#else
+ return 0;
+#endif