Merge branch 'game_protocol' of github.com:supertuxkart/stk-code into game_protocol

This commit is contained in:
hiker
2018-02-09 16:09:39 +11:00
25 changed files with 494 additions and 314 deletions

View File

@@ -10,6 +10,7 @@
android:icon="@drawable/icon"
android:banner="@drawable/banner"
android:hasCode="false"
android:isGame="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:hardwareAccelerated="true">
@@ -30,11 +31,12 @@
</activity>
</application>
<uses-sdk android:minSdkVersion="19" />
<uses-sdk android:targetSdkVersion="21" />
<uses-sdk android:minSdkVersion="19"
android:targetSdkVersion="21" />
<uses-feature android:glEsVersion="0x00020000" />
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.gamepad" android:required="false"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

View File

@@ -1,7 +1,7 @@
uniform sampler2D diffuse_map;
uniform sampler2D specular_map;
uniform sampler2D ssao_tex;
uniform sampler2D gloss_map;
uniform sampler2D normal_color;
uniform sampler2D diffuse_color;
uniform sampler2D depth_stencil;
uniform sampler2D light_scatter;
@@ -17,10 +17,11 @@ void main()
vec2 tc = gl_FragCoord.xy / u_screen;
vec4 diffuseMatColor = texture(diffuse_color, tc);
// Gloss map here is stored in red and green for metallic and emit map
// Real gloss channel is stored in normal and depth framebuffer .z
float metallicMapValue = texture(gloss_map, tc).x;
float emitMapValue = texture(gloss_map, tc).y;
// Polish map is stored in normal color framebuffer .z
// Metallic map is stored in normal color framebuffer .w
// Emit map is stored in diffuse color framebuffer.w
float metallicMapValue = texture(normal_color, tc).w;
float emitMapValue = diffuseMatColor.w;
float ao = texture(ssao_tex, tc).x;
vec3 DiffuseComponent = texture(diffuse_map, tc).xyz;
@@ -30,8 +31,8 @@ void main()
vec3 metallicMatColor = mix(vec3(0.04), diffuse_color_for_mix, metallicMapValue);
vec3 tmp = DiffuseComponent * mix(diffuseMatColor.xyz, vec3(0.0), metallicMapValue) + (metallicMatColor * SpecularComponent);
vec3 emitCol = diffuseMatColor.xyz * diffuseMatColor.xyz * diffuseMatColor.xyz * 15.;
vec4 color_1 = vec4(tmp * ao + (emitMapValue * emitCol), diffuseMatColor.a);
vec3 emitCol = diffuseMatColor.xyz + (diffuseMatColor.xyz * diffuseMatColor.xyz * emitMapValue * emitMapValue * 10.0);
vec4 color_1 = vec4(tmp * ao + (emitMapValue * emitCol), 1.0);
// Fog
float depth = texture(depth_stencil, tc).x;

View File

@@ -5,8 +5,7 @@ in vec3 normal;
in vec2 uv;
layout(location = 0) out vec4 o_diffuse_color;
layout(location = 1) out vec3 o_normal_depth;
layout(location = 2) out vec2 o_gloss_map;
layout(location = 1) out vec4 o_normal_color;
#stk_include "utils/encode_normal.frag"
#stk_include "utils/rgb_conversion.frag"
@@ -28,12 +27,15 @@ void main(void)
vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z));
col = vec4(new_color.r, new_color.g, new_color.b, col.a);
}
o_diffuse_color = vec4(col.xyz, 1.0);
#if defined(Advanced_Lighting_Enabled)
vec4 layer_2 = sampleTextureLayer2(uv);
o_normal_depth.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_depth.z = layer_2.x;
o_gloss_map = layer_2.yz;
o_diffuse_color = vec4(col.xyz, layer_2.z);
o_normal_color.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_color.zw = layer_2.xy;
#else
o_diffuse_color = vec4(col.xyz, 1.0);
#endif
}

View File

@@ -3,8 +3,7 @@ in vec2 uv;
in vec2 uv_two;
layout(location = 0) out vec4 o_diffuse_color;
layout(location = 1) out vec3 o_normal_depth;
layout(location = 2) out vec2 o_gloss_map;
layout(location = 1) out vec4 o_normal_color;
#stk_include "utils/encode_normal.frag"
#stk_include "utils/sp_texture_sampling.frag"
@@ -16,12 +15,15 @@ void main(void)
layer_two_tex.rgb = layer_two_tex.a * layer_two_tex.rgb;
vec3 final_color = layer_two_tex.rgb + color.rgb * (1.0 - layer_two_tex.a);
o_diffuse_color = vec4(final_color, 1.0);
#if defined(Advanced_Lighting_Enabled)
vec4 layer_2 = sampleTextureLayer2(uv);
o_normal_depth.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_depth.z = layer_2.x;
o_gloss_map = layer_2.yz;
o_diffuse_color = vec4(final_color, layer_2.z);
o_normal_color.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_color.zw = layer_2.xy;
#else
o_diffuse_color = vec4(final_color, 1.0);
#endif
}

View File

@@ -4,8 +4,7 @@ in vec3 normal;
in vec2 uv;
layout(location = 0) out vec4 o_diffuse_color;
layout(location = 1) out vec3 o_normal_depth;
layout(location = 2) out vec2 o_gloss_map;
layout(location = 1) out vec4 o_normal_color;
#stk_include "utils/encode_normal.frag"
#stk_include "utils/rgb_conversion.frag"
@@ -30,8 +29,12 @@ void main(void)
#if defined(Advanced_Lighting_Enabled)
vec4 layer_2 = sampleTextureLayer2(uv);
o_normal_depth.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_depth.z = layer_2.x;
o_gloss_map = 0.1 * layer_2.yz;
o_diffuse_color = vec4(col.xyz, layer_2.z);
o_normal_color.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_color.zw = layer_2.xy;
#else
o_diffuse_color = vec4(col.xyz, 1.0);
#endif
}

View File

@@ -1,16 +1,16 @@
in float hue_change;
in vec3 bitangent;
in vec4 color;
in float hue_change;
in vec3 normal;
in vec3 tangent;
in vec2 uv;
layout(location = 0) out vec4 o_diffuse_color;
layout(location = 1) out vec3 o_normal_depth;
layout(location = 2) out vec2 o_gloss_map;
layout(location = 1) out vec4 o_normal_color;
#stk_include "utils/encode_normal.frag"
#stk_include "utils/rgb_conversion.frag"
#stk_include "utils/sp_texture_sampling.frag"
#stk_include "utils/sp_normalMapOutput.frag"
void main()
{
@@ -33,11 +33,23 @@ void main()
}
vec3 final_color = col.xyz * color.xyz;
o_diffuse_color = vec4(final_color, 1.0);
#if defined(Advanced_Lighting_Enabled)
vec4 layer_3 = sampleTextureLayer3(uv);
vec4 layer_2 = sampleTextureLayer2(uv);
outputNormalMapPbrData(layer_3.rgb, layer_2.rgb);
vec4 layer_3 = sampleTextureLayer3(uv);
o_diffuse_color = vec4(final_color, layer_2.z);
vec3 tangent_space_normal = 2.0 * layer_3.xyz - 1.0;
vec3 frag_tangent = normalize(tangent);
vec3 frag_bitangent = normalize(bitangent);
vec3 frag_normal = normalize(normal);
mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal);
vec3 world_normal = t_b_n * tangent_space_normal;
o_normal_color.xy = 0.5 * EncodeNormal(normalize(world_normal)) + 0.5;
o_normal_color.zw = layer_2.xy;
#else
o_diffuse_color = vec4(final_color, 1.0);
#endif
}

View File

@@ -5,8 +5,7 @@ in vec3 normal;
in vec2 uv;
layout(location = 0) out vec4 o_diffuse_color;
layout(location = 1) out vec3 o_normal_depth;
layout(location = 2) out vec2 o_gloss_map;
layout(location = 1) out vec4 o_normal_color;
#stk_include "utils/encode_normal.frag"
#stk_include "utils/rgb_conversion.frag"
@@ -33,12 +32,15 @@ void main(void)
}
vec3 final_color = col.xyz * color.xyz;
o_diffuse_color = vec4(final_color, 1.0);
#if defined(Advanced_Lighting_Enabled)
vec4 layer_2 = sampleTextureLayer2(uv);
o_normal_depth.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_depth.z = layer_2.x;
o_gloss_map = layer_2.yz;
o_diffuse_color = vec4(final_color, layer_2.z);
o_normal_color.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_color.zw = layer_2.xy;
#else
o_diffuse_color = vec4(final_color, 1.0);
#endif
}

View File

@@ -3,8 +3,7 @@ in vec3 normal;
in vec2 uv;
layout(location = 0) out vec4 o_diffuse_color;
layout(location = 1) out vec3 o_normal_depth;
layout(location = 2) out vec2 o_gloss_map;
layout(location = 1) out vec4 o_normal_color;
#stk_include "utils/encode_normal.frag"
#stk_include "utils/sp_texture_sampling.frag"
@@ -21,8 +20,12 @@ void main(void)
o_diffuse_color = vec4(final_color, 1.0);
#if defined(Advanced_Lighting_Enabled)
o_normal_depth.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_depth.z = 0.0;
o_gloss_map = vec2(0.0, 0.1);
o_diffuse_color = vec4(final_color, 0.4);
o_normal_color.xy = 0.5 * EncodeNormal(normalize(normal)) + 0.5;
o_normal_color.zw = vec2(0.0);
#else
o_diffuse_color = vec4(final_color, 1.0);
#endif
}

View File

@@ -1,21 +0,0 @@
// This function encapsulate the computation of normal maps
in vec3 tangent;
in vec3 bitangent;
in vec3 normal;
void outputNormalMapPbrData(vec3 layer_3, vec3 layer_2)
{
vec3 tangent_space_normal = 2.0 * layer_3.xyz - 1.0;
vec3 frag_tangent = normalize(tangent);
vec3 frag_bitangent = normalize(bitangent);
vec3 frag_normal = normalize(normal);
mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal);
vec3 world_normal = t_b_n * tangent_space_normal;
o_normal_depth.xy = 0.5 * EncodeNormal(normalize(world_normal)) + 0.5;
o_normal_depth.z = layer_2.x;
o_gloss_map = layer_2.yz;
}

View File

@@ -48,7 +48,9 @@ CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param)
: CIrrDeviceStub(param),
Accelerometer(0),
Gyroscope(0),
IsMousePressed(false)
IsMousePressed(false),
GamepadAxisX(0),
GamepadAxisY(0)
{
#ifdef _DEBUG
setDebugName("CIrrDeviceAndroid");
@@ -391,218 +393,378 @@ s32 CIrrDeviceAndroid::handleInput(android_app* app, AInputEvent* androidEvent)
s32 status = 0;
switch (AInputEvent_getType(androidEvent))
int32_t source = AInputEvent_getSource(androidEvent);
int32_t type = AInputEvent_getType(androidEvent);
if (source == AINPUT_SOURCE_GAMEPAD ||
source == AINPUT_SOURCE_JOYSTICK ||
source == AINPUT_SOURCE_DPAD)
{
status = device->handleGamepad(androidEvent);
}
else
{
switch (type)
{
case AINPUT_EVENT_TYPE_MOTION:
{
status = device->handleTouch(androidEvent);
break;
}
case AINPUT_EVENT_TYPE_KEY:
{
status = device->handleKeyboard(androidEvent);
break;
}
default:
break;
}
}
return status;
}
s32 CIrrDeviceAndroid::handleTouch(AInputEvent* androidEvent)
{
s32 status = 0;
SEvent event;
event.EventType = EET_TOUCH_INPUT_EVENT;
s32 eventAction = AMotionEvent_getAction(androidEvent);
#if 0
// Useful for debugging. We might have to pass some of those infos on at some point.
// but preferably device independent (so iphone can use same irrlicht flags).
int32_t flags = AMotionEvent_getFlags(androidEvent);
os::Printer::log("flags: ", core::stringc(flags).c_str(), ELL_DEBUG);
int32_t metaState = AMotionEvent_getMetaState(androidEvent);
os::Printer::log("metaState: ", core::stringc(metaState).c_str(), ELL_DEBUG);
int32_t edgeFlags = AMotionEvent_getEdgeFlags(androidEvent);
os::Printer::log("edgeFlags: ", core::stringc(flags).c_str(), ELL_DEBUG);
#endif
bool touchReceived = true;
bool simulate_mouse = false;
core::position2d<s32> mouse_pos = core::position2d<s32>(0, 0);
switch (eventAction & AMOTION_EVENT_ACTION_MASK)
{
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_POINTER_DOWN:
event.TouchInput.Event = ETIE_PRESSED_DOWN;
break;
case AMOTION_EVENT_ACTION_MOVE:
event.TouchInput.Event = ETIE_MOVED;
break;
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_CANCEL:
event.TouchInput.Event = ETIE_LEFT_UP;
break;
default:
touchReceived = false;
break;
}
if (touchReceived)
{
s32 count = 1;
s32 idx = (eventAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
// Process all touches for move action.
if (event.TouchInput.Event == ETIE_MOVED)
{
count = AMotionEvent_getPointerCount(androidEvent);
idx = 0;
}
for (s32 i = 0; i < count; ++i)
{
event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, i + idx);
event.TouchInput.X = AMotionEvent_getX(androidEvent, i + idx);
event.TouchInput.Y = AMotionEvent_getY(androidEvent, i + idx);
if (event.TouchInput.ID >= 32)
continue;
TouchEventData& event_data = TouchEventsData[event.TouchInput.ID];
// Don't send move event when nothing changed
if (event_data.event == event.TouchInput.Event &&
event_data.x == event.TouchInput.X &&
event_data.y == event.TouchInput.Y)
continue;
event_data.event = event.TouchInput.Event;
event_data.x = event.TouchInput.X;
event_data.y = event.TouchInput.Y;
postEventFromUser(event);
if (event.TouchInput.ID == 0)
{
simulate_mouse = true;
mouse_pos.X = event.TouchInput.X;
mouse_pos.Y = event.TouchInput.Y;
}
}
status = 1;
}
// Simulate mouse event for first finger on multitouch device.
// This allows to click on GUI elements.
if (simulate_mouse)
{
CursorControl->setPosition(mouse_pos);
SEvent irrevent;
bool send_event = true;
switch (event.TouchInput.Event)
{
case ETIE_PRESSED_DOWN:
irrevent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
IsMousePressed = true;
break;
case ETIE_LEFT_UP:
irrevent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
IsMousePressed = false;
break;
case ETIE_MOVED:
irrevent.MouseInput.Event = EMIE_MOUSE_MOVED;
break;
default:
send_event = false;
break;
}
if (send_event)
{
irrevent.MouseInput.Control = false;
irrevent.MouseInput.Shift = false;
irrevent.MouseInput.ButtonStates = IsMousePressed ?
irr::EMBSM_LEFT : 0;
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
irrevent.MouseInput.X = mouse_pos.X;
irrevent.MouseInput.Y = mouse_pos.Y;
postEventFromUser(irrevent);
}
}
return status;
}
s32 CIrrDeviceAndroid::handleKeyboard(AInputEvent* androidEvent)
{
s32 status = 0;
bool ignore_event = false;
SEvent event;
event.EventType = EET_KEY_INPUT_EVENT;
event.KeyInput.Char = 0;
event.KeyInput.PressedDown = false;
event.KeyInput.Key = IRR_KEY_UNKNOWN;
int32_t keyCode = AKeyEvent_getKeyCode(androidEvent);
int32_t keyAction = AKeyEvent_getAction(androidEvent);
int32_t keyMetaState = AKeyEvent_getMetaState(androidEvent);
int32_t keyRepeat = AKeyEvent_getRepeatCount(androidEvent);
if (keyAction == AKEY_EVENT_ACTION_DOWN)
{
event.KeyInput.PressedDown = true;
}
else if (keyAction == AKEY_EVENT_ACTION_UP)
{
event.KeyInput.PressedDown = false;
}
else if (keyAction == AKEY_EVENT_ACTION_MULTIPLE)
{
// TODO: Multiple duplicate key events have occurred in a row,
// or a complex string is being delivered. The repeat_count
// property of the key event contains the number of times the
// given key code should be executed.
// I guess this might necessary for more complicated i18n key input,
// but don't see yet how to handle this correctly.
}
event.KeyInput.Shift = (keyMetaState & AMETA_SHIFT_ON ||
keyMetaState & AMETA_SHIFT_LEFT_ON ||
keyMetaState & AMETA_SHIFT_RIGHT_ON);
event.KeyInput.Control = (keyMetaState & AMETA_CTRL_ON ||
keyMetaState & AMETA_CTRL_LEFT_ON ||
keyMetaState & AMETA_CTRL_RIGHT_ON);
event.KeyInput.SystemKeyCode = (u32)keyCode;
event.KeyInput.Key = KeyMap[keyCode];
if (event.KeyInput.Key > 0)
{
getKeyChar(event);
}
// Handle an event when back button in pressed just like an escape key
// and also avoid repeating the event to avoid some strange behaviour
if (event.KeyInput.SystemKeyCode == AKEYCODE_BACK)
{
status = 1;
if (event.KeyInput.PressedDown == false || keyRepeat > 0)
{
ignore_event = true;
}
}
// Mark escape key event as handled by application to avoid receiving
// AKEYCODE_BACK key event
if (event.KeyInput.SystemKeyCode == AKEYCODE_ESCAPE)
{
status = 1;
}
if (!ignore_event)
{
postEventFromUser(event);
}
return status;
}
s32 CIrrDeviceAndroid::handleGamepad(AInputEvent* androidEvent)
{
s32 status = 0;
int32_t type = AInputEvent_getType(androidEvent);
switch (type)
{
case AINPUT_EVENT_TYPE_MOTION:
{
float axis_x = AMotionEvent_getAxisValue(androidEvent,
AMOTION_EVENT_AXIS_HAT_X, 0);
if (axis_x == 0)
{
axis_x = AMotionEvent_getAxisValue(androidEvent,
AMOTION_EVENT_AXIS_X, 0);
}
if (axis_x == 0)
{
axis_x = AMotionEvent_getAxisValue(androidEvent,
AMOTION_EVENT_AXIS_Z, 0);
}
float axis_y = AMotionEvent_getAxisValue(androidEvent,
AMOTION_EVENT_AXIS_HAT_Y, 0);
if (axis_y == 0)
{
axis_y = AMotionEvent_getAxisValue(androidEvent,
AMOTION_EVENT_AXIS_Y, 0);
}
if (axis_y == 0)
{
axis_y = AMotionEvent_getAxisValue(androidEvent,
AMOTION_EVENT_AXIS_RZ, 0);
}
SEvent event;
event.EventType = EET_TOUCH_INPUT_EVENT;
s32 eventAction = AMotionEvent_getAction(androidEvent);
#if 0
// Useful for debugging. We might have to pass some of those infos on at some point.
// but preferably device independent (so iphone can use same irrlicht flags).
int32_t flags = AMotionEvent_getFlags(androidEvent);
os::Printer::log("flags: ", core::stringc(flags).c_str(), ELL_DEBUG);
int32_t metaState = AMotionEvent_getMetaState(androidEvent);
os::Printer::log("metaState: ", core::stringc(metaState).c_str(), ELL_DEBUG);
int32_t edgeFlags = AMotionEvent_getEdgeFlags(androidEvent);
os::Printer::log("edgeFlags: ", core::stringc(flags).c_str(), ELL_DEBUG);
#endif
bool touchReceived = true;
bool simulate_mouse = false;
core::position2d<s32> mouse_pos = core::position2d<s32>(0, 0);
switch (eventAction & AMOTION_EVENT_ACTION_MASK)
{
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_POINTER_DOWN:
event.TouchInput.Event = ETIE_PRESSED_DOWN;
break;
case AMOTION_EVENT_ACTION_MOVE:
event.TouchInput.Event = ETIE_MOVED;
break;
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_CANCEL:
event.TouchInput.Event = ETIE_LEFT_UP;
break;
default:
touchReceived = false;
break;
}
event.EventType = EET_KEY_INPUT_EVENT;
event.KeyInput.Char = 0;
event.KeyInput.Shift = false;
event.KeyInput.Control = false;
event.KeyInput.SystemKeyCode = 0;
if (touchReceived)
{
s32 count = 1;
s32 idx = (eventAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
// Process all touches for move action.
if (event.TouchInput.Event == ETIE_MOVED)
{
count = AMotionEvent_getPointerCount(androidEvent);
idx = 0;
}
for (s32 i = 0; i < count; ++i)
{
event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, i + idx);
event.TouchInput.X = AMotionEvent_getX(androidEvent, i + idx);
event.TouchInput.Y = AMotionEvent_getY(androidEvent, i + idx);
if (event.TouchInput.ID >= 32)
continue;
TouchEventData& event_data = device->TouchEventsData[event.TouchInput.ID];
// Don't send move event when nothing changed
if (event_data.event == event.TouchInput.Event &&
event_data.x == event.TouchInput.X &&
event_data.y == event.TouchInput.Y)
continue;
event_data.event = event.TouchInput.Event;
event_data.x = event.TouchInput.X;
event_data.y = event.TouchInput.Y;
device->postEventFromUser(event);
if (event.TouchInput.ID == 0)
{
simulate_mouse = true;
mouse_pos.X = event.TouchInput.X;
mouse_pos.Y = event.TouchInput.Y;
}
}
status = 1;
}
float deadzone = 0.3f;
// Simulate mouse event for first finger on multitouch device.
// This allows to click on GUI elements.
if (simulate_mouse)
axis_x = axis_x > deadzone || axis_x < -deadzone ? axis_x : 0;
axis_y = axis_y > deadzone || axis_y < -deadzone ? axis_y : 0;
if (axis_x != GamepadAxisX)
{
device->CursorControl->setPosition(mouse_pos);
SEvent irrevent;
bool send_event = true;
switch (event.TouchInput.Event)
if (GamepadAxisX != 0)
{
case ETIE_PRESSED_DOWN:
irrevent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN;
device->IsMousePressed = true;
break;
case ETIE_LEFT_UP:
irrevent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
device->IsMousePressed = false;
break;
case ETIE_MOVED:
irrevent.MouseInput.Event = EMIE_MOUSE_MOVED;
break;
default:
send_event = false;
break;
event.KeyInput.PressedDown = false;
event.KeyInput.Key = GamepadAxisX < 0 ? IRR_KEY_LEFT
: IRR_KEY_RIGHT;
postEventFromUser(event);
}
if (send_event)
if (axis_x != 0)
{
irrevent.MouseInput.Control = false;
irrevent.MouseInput.Shift = false;
irrevent.MouseInput.ButtonStates = device->IsMousePressed ?
irr::EMBSM_LEFT : 0;
irrevent.EventType = EET_MOUSE_INPUT_EVENT;
irrevent.MouseInput.X = mouse_pos.X;
irrevent.MouseInput.Y = mouse_pos.Y;
device->postEventFromUser(irrevent);
event.KeyInput.PressedDown = true;
event.KeyInput.Key = axis_x < 0 ? IRR_KEY_LEFT : IRR_KEY_RIGHT;
postEventFromUser(event);
}
GamepadAxisX = axis_x;
}
if (axis_y != GamepadAxisY)
{
if (GamepadAxisY != 0)
{
event.KeyInput.PressedDown = false;
event.KeyInput.Key = GamepadAxisY < 0 ? IRR_KEY_UP
: IRR_KEY_DOWN;
postEventFromUser(event);
}
if (axis_y != 0)
{
event.KeyInput.PressedDown = true;
event.KeyInput.Key = axis_y < 0 ? IRR_KEY_UP : IRR_KEY_DOWN;
postEventFromUser(event);
}
GamepadAxisY = axis_y;
}
status = 1;
break;
}
case AINPUT_EVENT_TYPE_KEY:
{
bool ignore_event = false;
bool ignore = false;
int32_t keyCode = AKeyEvent_getKeyCode(androidEvent);
int32_t keyAction = AKeyEvent_getAction(androidEvent);
int32_t keyRepeat = AKeyEvent_getRepeatCount(androidEvent);
SEvent event;
event.EventType = EET_KEY_INPUT_EVENT;
event.KeyInput.Char = 0;
event.KeyInput.PressedDown = false;
event.KeyInput.Key = IRR_KEY_UNKNOWN;
int32_t keyCode = AKeyEvent_getKeyCode(androidEvent);
int32_t keyAction = AKeyEvent_getAction(androidEvent);
int32_t keyMetaState = AKeyEvent_getMetaState(androidEvent);
int32_t keyRepeat = AKeyEvent_getRepeatCount(androidEvent);
if (keyAction == AKEY_EVENT_ACTION_DOWN)
{
event.KeyInput.PressedDown = true;
}
else if (keyAction == AKEY_EVENT_ACTION_UP)
{
event.KeyInput.PressedDown = false;
}
else if (keyAction == AKEY_EVENT_ACTION_MULTIPLE)
{
// TODO: Multiple duplicate key events have occurred in a row,
// or a complex string is being delivered. The repeat_count
// property of the key event contains the number of times the
// given key code should be executed.
// I guess this might necessary for more complicated i18n key input,
// but don't see yet how to handle this correctly.
}
event.KeyInput.Shift = (keyMetaState & AMETA_SHIFT_ON ||
keyMetaState & AMETA_SHIFT_LEFT_ON ||
keyMetaState & AMETA_SHIFT_RIGHT_ON);
event.KeyInput.Control = (keyMetaState & AMETA_CTRL_ON ||
keyMetaState & AMETA_CTRL_LEFT_ON ||
keyMetaState & AMETA_CTRL_RIGHT_ON);
event.KeyInput.PressedDown = (keyAction == AKEY_EVENT_ACTION_DOWN);
event.KeyInput.Shift = false;
event.KeyInput.Control = false;
event.KeyInput.SystemKeyCode = (u32)keyCode;
event.KeyInput.Key = device->KeyMap[keyCode];
if (event.KeyInput.Key > 0)
{
device->getKeyChar(event);
}
event.KeyInput.Key = KeyMap[keyCode];
// Handle an event when back button in pressed just like an escape key
// and also avoid repeating the event to avoid some strange behaviour
if (event.KeyInput.SystemKeyCode == AKEYCODE_BACK)
{
status = 1;
if (event.KeyInput.PressedDown == false || keyRepeat > 0)
{
ignore_event = true;
}
ignore = (event.KeyInput.PressedDown == false || keyRepeat > 0);
}
// Mark escape key event as handled by application to avoid receiving
// AKEYCODE_BACK key event
if (event.KeyInput.SystemKeyCode == AKEYCODE_ESCAPE)
{
status = 1;
}
if (!ignore_event)
{
device->postEventFromUser(event);
}
postEventFromUser(event);
break;
}
default:
break;
}
return status;
}
@@ -711,21 +873,21 @@ void CIrrDeviceAndroid::createKeyMap()
KeyMap[AKEYCODE_SWITCH_CHARSET] = IRR_KEY_UNKNOWN;
// following look like controller inputs
KeyMap[AKEYCODE_BUTTON_A] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_B] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_C] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_X] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_Y] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_Z] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_L1] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_R1] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_L2] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_R2] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_THUMBL] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_THUMBR] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_START] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_SELECT] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_MODE] = IRR_KEY_UNKNOWN;
KeyMap[AKEYCODE_BUTTON_A] = IRR_KEY_RETURN;
KeyMap[AKEYCODE_BUTTON_B] = IRR_KEY_BACK;
KeyMap[AKEYCODE_BUTTON_C] = IRR_KEY_2;
KeyMap[AKEYCODE_BUTTON_X] = IRR_KEY_3;
KeyMap[AKEYCODE_BUTTON_Y] = IRR_KEY_4;
KeyMap[AKEYCODE_BUTTON_Z] = IRR_KEY_5;
KeyMap[AKEYCODE_BUTTON_L1] = IRR_KEY_6;
KeyMap[AKEYCODE_BUTTON_R1] = IRR_KEY_7;
KeyMap[AKEYCODE_BUTTON_L2] = IRR_KEY_8;
KeyMap[AKEYCODE_BUTTON_R2] = IRR_KEY_9;
KeyMap[AKEYCODE_BUTTON_THUMBL] = IRR_KEY_RETURN;
KeyMap[AKEYCODE_BUTTON_THUMBR] = IRR_KEY_RETURN;
KeyMap[AKEYCODE_BUTTON_START] = IRR_KEY_RETURN;
KeyMap[AKEYCODE_BUTTON_SELECT] = IRR_KEY_BACK;
KeyMap[AKEYCODE_BUTTON_MODE] = IRR_KEY_MENU;
KeyMap[AKEYCODE_ESCAPE] = IRR_KEY_ESCAPE;
KeyMap[AKEYCODE_FORWARD_DEL] = IRR_KEY_DELETE;

View File

@@ -121,6 +121,8 @@ namespace irr
TouchEventData TouchEventsData[32];
bool IsMousePressed;
float GamepadAxisX;
float GamepadAxisY;
video::SExposedVideoData ExposedVideoData;
@@ -134,6 +136,10 @@ namespace irr
static void handleAndroidCommand(android_app* app, int32_t cmd);
static s32 handleInput(android_app* app, AInputEvent* event);
s32 handleTouch(AInputEvent* androidEvent);
s32 handleKeyboard(AInputEvent* androidEvent);
s32 handleGamepad(AInputEvent* androidEvent);
};
} // end namespace irr

View File

@@ -279,13 +279,14 @@ void STKConfig::getAllData(const XMLNode * root)
if (const XMLNode *camera = root->getNode("camera"))
{
for (int i = 0; i < 4; i++)
camera->get("fov-1", &m_camera_fov[0]);
camera->get("fov-2", &m_camera_fov[1]);
camera->get("fov-3", &m_camera_fov[2]);
camera->get("fov-4", &m_camera_fov[3]);
for (unsigned int i = 4; i < MAX_PLAYER_COUNT; i++)
{
camera->get("fov-" + std::to_string(i + 1), &m_camera_fov[i]);
}
for (int i = 4; i < MAX_PLAYER_COUNT; i++)
{
camera->get("fov-" + std::to_string(4), &m_camera_fov[i]);
camera->get("fov-4", &m_camera_fov[i]);
}
camera->get("cutscene-fov", &m_cutscene_fov);
}

View File

@@ -163,15 +163,17 @@ void Camera::setKart(AbstractKart *new_kart)
*/
void Camera::setupCamera()
{
m_viewport = irr_driver->GetSplitscreenWindow(m_index);
m_viewport = irr_driver->getSplitscreenWindow(m_index);
m_aspect = (float)((float)(m_viewport.getWidth()) / (float)(m_viewport.getHeight()));
m_scaling = core::vector2df(
irr_driver->getActualScreenSize().Width / m_viewport.getWidth() ,
irr_driver->getActualScreenSize().Height / m_viewport.getHeight());
m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov[race_manager->getNumLocalPlayers() - 1];
m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov
[race_manager->getNumLocalPlayers() > 0 ?
race_manager->getNumLocalPlayers() - 1 : 0];
m_camera->setFOV(m_fov);
m_camera->setAspectRatio(m_aspect);
m_camera->setFarValue(Track::getCurrentTrack()->getCameraFar());

View File

@@ -230,7 +230,7 @@ void IrrDriver::updateConfigIfRelevant()
}
#endif // !SERVER_ONLY
} // updateConfigIfRelevant
core::recti IrrDriver::GetSplitscreenWindow(int WindowNum)
core::recti IrrDriver::getSplitscreenWindow(int WindowNum)
{
const int playernum = race_manager->getNumLocalPlayers();
const float playernum_sqrt = sqrt(playernum);

View File

@@ -203,7 +203,7 @@ public:
void increaseObjectCount();
core::array<video::IRenderTarget> &getMainSetup();
void updateConfigIfRelevant();
core::recti GetSplitscreenWindow(int WindowNum);
core::recti getSplitscreenWindow(int WindowNum);
void setAllMaterialFlags(scene::IMesh *mesh) const;
scene::IAnimatedMesh *getAnimatedMesh(const std::string &name);
scene::IMesh *getMesh(const std::string &name);

View File

@@ -118,8 +118,7 @@ RTT::RTT(unsigned int width, unsigned int height, float rtt_scale,
}
if (CVS->isDeferredEnabled())
{
m_render_target_textures[RTT_NORMAL_AND_DEPTH] = generateRTT(res, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
m_render_target_textures[RTT_SP_GLOSS] = generateRTT(res, GL_RG8, GL_RG, GL_UNSIGNED_BYTE);
m_render_target_textures[RTT_NORMAL_AND_DEPTH] = generateRTT(res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
m_render_target_textures[RTT_SP_DIFF_COLOR] = generateRTT(res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
m_render_target_textures[RTT_RGBA_2] = generateRTT(res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
m_render_target_textures[RTT_DIFFUSE] = generateRTT(res, diffuse_specular_internal_format, rgb_format, type);
@@ -181,7 +180,6 @@ RTT::RTT(unsigned int width, unsigned int height, float rtt_scale,
somevector.clear();
somevector.push_back(m_render_target_textures[RTT_SP_DIFF_COLOR]);
somevector.push_back(m_render_target_textures[RTT_NORMAL_AND_DEPTH]);
somevector.push_back(m_render_target_textures[RTT_SP_GLOSS]);
m_frame_buffers[FBO_SP] = new FrameBuffer(somevector, m_depth_stencil_tex, res.Width, res.Height);
somevector.clear();

View File

@@ -65,7 +65,6 @@ enum TypeRTT : unsigned int
{
RTT_COLOR = 0,
RTT_NORMAL_AND_DEPTH,
RTT_SP_GLOSS,
RTT_SP_DIFF_COLOR, // RGBA
RTT_RGBA_2,
RTT_DIFFUSE,

View File

@@ -207,16 +207,16 @@ public:
assignSamplerNames(0, "diffuse_map", ST_NEAREST_FILTERED,
1, "specular_map", ST_NEAREST_FILTERED,
2, "ssao_tex", ST_NEAREST_FILTERED,
3, "gloss_map", ST_NEAREST_FILTERED,
3, "normal_color", ST_NEAREST_FILTERED,
4, "diffuse_color", ST_NEAREST_FILTERED,
5, "depth_stencil", ST_NEAREST_FILTERED,
6, "light_scatter", ST_NEAREST_FILTERED);
} // CombineDiffuseColor
// ------------------------------------------------------------------------
void render(GLuint dm, GLuint sm, GLuint st, GLuint gm, GLuint dc,
void render(GLuint dm, GLuint sm, GLuint st, GLuint nt, GLuint dc,
GLuint ds, GLuint lt, const std::array<float, 4> & bg_color)
{
setTextureUnits(dm, sm, st, gm, dc, ds, lt);
setTextureUnits(dm, sm, st, nt, dc, ds, lt);
drawFullScreenEffect(bg_color);
} // render
}; // CombineDiffuseColor
@@ -259,10 +259,8 @@ void ShaderBasedRenderer::renderSceneDeferred(scene::ICameraSceneNode * const ca
{
m_rtts->getFBO(FBO_SP).bind();
float clear_color_empty[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
float clear_color_gloss[4] = { 0.1f, 0.1f, 0.0f, 0.0f };
glClearBufferfv(GL_COLOR, 0, clear_color_empty);
glClearBufferfv(GL_COLOR, 1, clear_color_empty);
glClearBufferfv(GL_COLOR, 2, clear_color_gloss);
glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SOLID_PASS));
SP::draw(SP::RP_1ST, SP::DCT_NORMAL);
@@ -352,7 +350,7 @@ void ShaderBasedRenderer::renderSceneDeferred(scene::ICameraSceneNode * const ca
m_rtts->getRenderTarget(RTT_DIFFUSE),
m_rtts->getRenderTarget(RTT_SPECULAR),
m_rtts->getRenderTarget(RTT_HALF1_R),
m_rtts->getRenderTarget(RTT_SP_GLOSS),
m_rtts->getRenderTarget(RTT_NORMAL_AND_DEPTH),
m_rtts->getRenderTarget(RTT_SP_DIFF_COLOR),
m_rtts->getDepthStencilTexture(),
m_rtts->getRenderTarget(RTT_HALF1), !m_skybox ?

View File

@@ -1245,6 +1245,8 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget,
BoxRenderParams* params;
SpinnerWidget* q = dynamic_cast<SpinnerWidget*>(widget);
std::string texture = "squareFocusHalo::neutral";
SColorf color_rgb = { 1,1,1,1 };
if(q->getUseBackgroundColor())
{
int player_id=q->getSpinnerWidgetPlayerID();
@@ -1252,17 +1254,9 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget,
params = &SkinConfig::m_render_params[
"spinner::deactivated"];
SColorf color_rgb = GetPlayerColor(player_id);
widget->m_skin_r = color_rgb.r * 255.0F;
widget->m_skin_g = color_rgb.g * 255.0F;
widget->m_skin_b = color_rgb.b * 255.0F;
if (player_id == 0)
{
color_rgb = { 1,1,1,1 };
}
color_rgb = GetPlayerColor(player_id);
texture = "squareFocusHaloBW::neutral";
}
else if (widget->m_deactivated)
{
@@ -1276,6 +1270,10 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget,
{
params=&SkinConfig::m_render_params["spinner::neutral"];
}
widget->m_skin_r = color_rgb.r * 255.0f;
widget->m_skin_g = color_rgb.g * 255.0f;
widget->m_skin_b = color_rgb.b * 255.0f;
for (int i = 1; i < MAX_PLAYER_COUNT + 1; i++)
{
if (widget->isFocusedForPlayer(i - 1)) {
@@ -1287,7 +1285,7 @@ void Skin::drawSpinnerBody(const core::recti &rect, Widget* widget,
drawBoxFromStretchableTexture(widget, rect2,
SkinConfig::m_render_params["squareFocusHaloBW::neutral"]);
SkinConfig::m_render_params[texture]);
//TODO add squarefocushalo0
}

View File

@@ -241,7 +241,7 @@ void World::init()
Camera::createCamera(World::getWorld()->getKart(0), 0);
} // if server with graphics of is watching replay
} // if getNumCameras()==0
} // if getNumCameras()==0
} // init
//-----------------------------------------------------------------------------

View File

@@ -491,15 +491,18 @@ public:
} // getNumLocalPlayers
// ------------------------------------------------------------------------
/** Returns true if the split screen display leaves an empty space that
* can be used to display the minimap.
*/
bool getIfEmptyScreenSpaceExists() const
{
const float Sqrt = sqrt(getNumLocalPlayers());
const int rows = ceil(Sqrt);
const int cols = round(Sqrt);
const float sqrt_num_players = sqrtf((float)getNumLocalPlayers());
const int rows = (int)ceil(sqrt_num_players);
const int cols = (int)round(sqrt_num_players);
const int total_spaces = rows * cols;
return (total_spaces - getNumLocalPlayers() > 0);
} // getNumLocalPlayers
// ------------------------------------------------------------------------
} // getIfEmptyScreenSpaceExists
// ------------------------------------------------------------------------
/** Returns the selected number of karts (selected number of players and
* AI karts. */
unsigned int getNumberOfKarts() const {return m_num_karts; }

View File

@@ -23,6 +23,7 @@
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "guiengine/widgets/player_kart_widget.hpp"
#include "input/device_manager.hpp"
#include "items/item_manager.hpp"
#include "karts/kart_properties.hpp"
#include "karts/kart_properties_manager.hpp"
@@ -157,6 +158,7 @@ void NetworkKartSelectionScreen::playerConfirm(const int playerID)
clrp->requestKartSelection(players[i]->getGlobalPlayerId(),
selection );
}
input_manager->getDeviceManager()->setAssignMode(ASSIGN);
}
} // playerConfirm

View File

@@ -195,7 +195,7 @@ void RaceGUI::renderGlobal(float dt)
{
static video::SColor black = video::SColor(255,0,0,0);
GL32_draw2DRectangle(black, irr_driver->GetSplitscreenWindow(
GL32_draw2DRectangle(black, irr_driver->getSplitscreenWindow(
race_manager->getNumLocalPlayers()));
}
@@ -253,7 +253,15 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt)
drawPlungerInFace(camera, dt);
scaling *= float(viewport.getWidth()) / float(irr_driver->getActualScreenSize().Width); // scale race GUI along screen size
if (viewport.getWidth() != irr_driver->getActualScreenSize().Width)
{
scaling *= float(viewport.getWidth()) / float(irr_driver->getActualScreenSize().Width); // scale race GUI along screen size
}
else
{
scaling *= float(viewport.getWidth()) / 800.0f; // scale race GUI along screen size
}
drawAllMessages(kart, viewport, scaling);
if(!World::getWorld()->isRacePhase()) return;
@@ -369,7 +377,7 @@ void RaceGUI::drawGlobalTimer()
if (race_manager->getIfEmptyScreenSpaceExists())
{
pos -= core::vector2d<s32>(0, pos.LowerRightCorner.Y / 2);
pos += core::vector2d<s32>(0, irr_driver->getActualScreenSize().Height - irr_driver->GetSplitscreenWindow(0).getHeight());
pos += core::vector2d<s32>(0, irr_driver->getActualScreenSize().Height - irr_driver->getSplitscreenWindow(0).getHeight());
}
gui::ScalableFont* font = (use_digit_font ? GUIEngine::getHighresDigitFont() : GUIEngine::getFont());
@@ -888,6 +896,8 @@ void RaceGUI::drawLap(const AbstractKart* kart,
core::recti pos;
pos.UpperLeftCorner.Y = viewport.UpperLeftCorner.Y + m_font_height;
// If the time display in the top right is in this viewport,
// move the lap/rank display down a little bit so that it is
// displayed under the time.
@@ -897,10 +907,6 @@ void RaceGUI::drawLap(const AbstractKart* kart,
{
pos.UpperLeftCorner.Y += m_font_height;
}
else
{
pos.UpperLeftCorner.Y = viewport.UpperLeftCorner.Y + m_font_height;
}
pos.LowerRightCorner.Y = viewport.LowerRightCorner.Y+20;
pos.UpperLeftCorner.X = viewport.LowerRightCorner.X
- m_lap_width - 10;

View File

@@ -244,7 +244,7 @@ void RaceGUIBase::drawAllMessages(const AbstractKart* kart,
}
// First line of text somewhat under the top of the viewport.
y = (int)(viewport.UpperLeftCorner.Y + 20);
y = viewport.getCenter().Y;
gui::ScalableFont* font = GUIEngine::getFont();
gui::ScalableFont* big_font = GUIEngine::getTitleFont();
@@ -253,7 +253,6 @@ void RaceGUIBase::drawAllMessages(const AbstractKart* kart,
if (race_manager->getNumLocalPlayers() > 2)
{
font = GUIEngine::getSmallFont();
font_height = m_small_font_max_height;
}
irr_driver->getVideoDriver()->enableMaterial2D(); // seems like we need to remind irrlicht from time to time to use the Material2D
@@ -348,10 +347,10 @@ void RaceGUIBase::drawPowerupIcons(const AbstractKart* kart,
int nSize = (int)(64.0f * scale);
int itemSpacing = (int)(scale * 30);
int itemSpacing = (int)(scale * 32.0f);
int x1 = viewport.UpperLeftCorner.X + viewport.getWidth()/2
- (n * itemSpacing)/2;
int x1 = viewport.UpperLeftCorner.X + (viewport.getWidth()/2)
- ((n * itemSpacing)/2);
int y1 = viewport.UpperLeftCorner.Y + (int)(20 * scaling.Y);
int x2 = 0;
@@ -364,7 +363,7 @@ void RaceGUIBase::drawPowerupIcons(const AbstractKart* kart,
for ( int i = 0 ; i < n ; i++ )
{
x2 = (int)(x1+i*itemSpacing);
x2 = (int)((x1+i*itemSpacing) - (itemSpacing / 2));
core::rect<s32> pos(x2, y1, x2+nSize, y1+nSize);
draw2DImage(t, pos, rect, NULL,
NULL, true);
@@ -667,7 +666,7 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
// Special case : when 3 players play, use 4th window to display such stuff
if (race_manager->getIfEmptyScreenSpaceExists())
{
irr::core::recti Last_Space = irr_driver->GetSplitscreenWindow(race_manager->getNumLocalPlayers());
irr::core::recti Last_Space = irr_driver->getSplitscreenWindow(race_manager->getNumLocalPlayers());
x_base = Last_Space.UpperLeftCorner.X;
y_base = Last_Space.UpperLeftCorner.Y;
y_space = irr_driver->getActualScreenSize().Height - y_base;

View File

@@ -186,7 +186,7 @@ void RaceGUIOverworld::renderGlobal(float dt)
const int rows = ceil(Sqrt);
const int cols = round(Sqrt);
static video::SColor black = video::SColor(255,0,0,0);
GL32_draw2DRectangle(black, irr_driver->GetSplitscreenWindow(
GL32_draw2DRectangle(black, irr_driver->getSplitscreenWindow(
race_manager->getNumLocalPlayers()));
}