// Copyright (c) 2014 Alex Diener. All rights reserved. #include "glgraphics/GLIncludes.h" #include "shell/Shell.h" #include "shell/ShellKeyCodes.h" #include "utilities/IOUtilities.h" #include "watertowerclassic/LevelFileIO.h" #include "watertowerclassic/ControlsScreen.h" #include "watertowerclassic/ShellStateGlobals.h" #include "watertowerclassic/SharedEvents.h" #include #include #include #if defined(STEM_PLATFORM_macosx) #include "nsopenglshell/NSOpenGLShell.h" #elif defined(STEM_PLATFORM_win32) || defined(STEM_PLATFORM_win64) #include "wglshell/WGLShell.h" #elif defined(STEM_PLATFORM_linux32) || defined(STEM_PLATFORM_linux64) #include "glxshell/GLXShell.h" #endif #define SUPERCLASS Screen enum { MENU_ITEM_LEFT, MENU_ITEM_RIGHT, MENU_ITEM_DOWN, MENU_ITEM_UP, MENU_ITEM_JUMP, MENU_ITEM_ACTION, MENU_ITEM_PAUSE, MENU_ITEM_DONE, MENU_ITEM_COUNT }; static const char * actionIDs[MENU_ITEM_COUNT - 1]; ControlsScreen * ControlsScreen_create(GameSession * gameSession) { stemobject_create_implementation(ControlsScreen, init, gameSession) } bool ControlsScreen_init(ControlsScreen * self, GameSession * gameSession) { call_super(init, self); self->activate = ControlsScreen_activate; self->deactivate = ControlsScreen_deactivate; self->dispose = ControlsScreen_dispose; self->gameSession = gameSession; self->inputController = InputController_create(gameSession->inputMap, "left", "right", "down", "up", "jump", "action", "pause", NULL); self->menuItemIndex = 0; self->waitingForInput = false; glGenBuffersARB(1, &self->vertexBufferID); glGenBuffersARB(1, &self->indexBufferID); self->bitmapFont = ResourceManager_referenceResource(self->gameSession->resourceManager, "bitmap_font", "pixelfont.json"); if (actionIDs[0] == NULL) { actionIDs[0] = ATOM("left"); actionIDs[1] = ATOM("right"); actionIDs[2] = ATOM("down"); actionIDs[3] = ATOM("up"); actionIDs[4] = ATOM("jump"); actionIDs[5] = ATOM("action"); actionIDs[6] = ATOM("pause"); } return true; } void ControlsScreen_dispose(ControlsScreen * self) { glDeleteBuffersARB(1, &self->vertexBufferID); glDeleteBuffersARB(1, &self->indexBufferID); ResourceManager_releaseResource(self->gameSession->resourceManager, "bitmap_font", "pixelfont.json"); InputController_dispose(self->inputController); call_super(dispose, self); } static void menuDown(ControlsScreen * self) { self->menuItemIndex += 1; self->menuItemIndex %= MENU_ITEM_COUNT; Shell_redisplay(); } static void menuUp(ControlsScreen * self) { self->menuItemIndex += MENU_ITEM_COUNT - 1; self->menuItemIndex %= MENU_ITEM_COUNT; Shell_redisplay(); } static void menuAction(ControlsScreen * self) { if (self->menuItemIndex == MENU_ITEM_DONE) { GameSession_saveControlBindings(self->gameSession); InputController_reset(self->inputController); ScreenManager_transition(self->screenManager, "back"); } else { self->waitingForInput = true; Shell_redisplay(); } } static void menuBack(ControlsScreen * self) { GameSession_saveControlBindings(self->gameSession); InputController_reset(self->inputController); ScreenManager_transition(self->screenManager, "back"); } static bool mouseDown(Atom eventID, void * eventData, void * context) { struct mouseEvent * event = eventData; ControlsScreen * self = context; if (event->position.y >= 182.0f) { if (event->position.y < 406.0f) { self->menuItemIndex = (event->position.y - 182.0f) / 32.0f; if (self->menuItemIndex >= MENU_ITEM_COUNT - 1) { self->menuItemIndex = MENU_ITEM_COUNT - 2; } menuAction(self); } else if (event->position.y > 438.0f && event->position.y < 470.0f) { self->menuItemIndex = MENU_ITEM_COUNT - 1; menuAction(self); } } return false; } static bool keyDown(Atom eventID, void * eventData, void * context) { struct keyEvent * event = eventData; ControlsScreen * self = context; if (event->isRepeat) { return false; } if (self->waitingForInput) { if (event->keyCode != KEYBOARD_ESCAPE) { unsigned int actionIndex; for (actionIndex = 0; actionIndex < MENU_ITEM_COUNT - 1; actionIndex++) { if (((self->menuItemIndex == MENU_ITEM_UP || self->menuItemIndex == MENU_ITEM_DOWN) && actionIndex == MENU_ITEM_ACTION) || ((actionIndex == MENU_ITEM_UP || actionIndex == MENU_ITEM_DOWN) && self->menuItemIndex == MENU_ITEM_ACTION)) { continue; } InputMap_unbindKey(self->gameSession->inputMap, actionIDs[actionIndex], event->keyCode); } InputMap_unbindAllKeysForAction(self->gameSession->inputMap, actionIDs[self->menuItemIndex]); InputMap_bindKey(self->gameSession->inputMap, actionIDs[self->menuItemIndex], event->keyCode); } self->waitingForInput = false; Shell_redisplay(); return true; } switch (event->keyCode) { case KEYBOARD_ESCAPE: menuBack(self); return true; case KEYBOARD_RETURN_OR_ENTER: case KEYBOARD_SPACEBAR: InputController_triggerAction(self->inputController, ATOM("jump")); return true; case KEYBOARD_DOWN_ARROW: InputController_triggerAction(self->inputController, ATOM("down")); return true; case KEYBOARD_UP_ARROW: InputController_triggerAction(self->inputController, ATOM("up")); return true; } return InputController_keyDown(self->inputController, event->keyCode); } static bool keyUp(Atom eventID, void * eventData, void * context) { struct keyEvent * event = eventData; ControlsScreen * self = context; switch (event->keyCode) { case KEYBOARD_RETURN_OR_ENTER: case KEYBOARD_SPACEBAR: InputController_releaseAction(self->inputController, ATOM("jump")); return true; case KEYBOARD_DOWN_ARROW: InputController_releaseAction(self->inputController, ATOM("down")); return true; case KEYBOARD_UP_ARROW: InputController_releaseAction(self->inputController, ATOM("up")); return true; } return InputController_keyUp(self->inputController, event->keyCode); } static bool gamepadButtonDown(Atom eventID, void * eventData, void * context) { struct gamepadButtonEvent * event = eventData; ControlsScreen * self = context; if (self->waitingForInput) { InputMap_unbindAllButtonsOnDeviceForAction(self->gameSession->inputMap, event->device->vendorID, event->device->productID, actionIDs[self->menuItemIndex]); InputMap_unbindAllAxesOnDeviceForAction(self->gameSession->inputMap, event->device->vendorID, event->device->productID, actionIDs[self->menuItemIndex]); InputMap_unbindAllActionsForButton(self->gameSession->inputMap, event->device->vendorID, event->device->productID, event->buttonID); InputMap_bindButton(self->gameSession->inputMap, actionIDs[self->menuItemIndex], event->device->vendorID, event->device->productID, event->buttonID); self->waitingForInput = false; Shell_redisplay(); return true; } return InputController_gamepadButtonDown(self->inputController, event->device->vendorID, event->device->productID, event->buttonID); } static bool gamepadButtonUp(Atom eventID, void * eventData, void * context) { struct gamepadButtonEvent * event = eventData; ControlsScreen * self = context; return InputController_gamepadButtonUp(self->inputController, event->device->vendorID, event->device->productID, event->buttonID); } #define TRIGGER_THRESHOLD 0.5f #define RELEASE_THRESHOLD 0.375f static bool gamepadAxisMove(Atom eventID, void * eventData, void * context) { struct gamepadAxisEvent * event = eventData; ControlsScreen * self = context; if (self->waitingForInput) { if (fabs(event->lastValue) < TRIGGER_THRESHOLD && fabs(event->value) > TRIGGER_THRESHOLD) { InputMap_unbindAllButtonsOnDeviceForAction(self->gameSession->inputMap, event->device->vendorID, event->device->productID, actionIDs[self->menuItemIndex]); InputMap_unbindAllAxesOnDeviceForAction(self->gameSession->inputMap, event->device->vendorID, event->device->productID, actionIDs[self->menuItemIndex]); InputMap_unbindAllActionsForAxis(self->gameSession->inputMap, event->device->vendorID, event->device->productID, event->axisID, event->value > 0); InputMap_bindAxis(self->gameSession->inputMap, actionIDs[self->menuItemIndex], event->device->vendorID, event->device->productID, event->axisID, event->value < 0 ? -TRIGGER_THRESHOLD : TRIGGER_THRESHOLD, event->value < 0 ? -RELEASE_THRESHOLD : RELEASE_THRESHOLD); self->waitingForInput = false; Shell_redisplay(); return true; } return false; } return InputController_gamepadAxisMoved(self->inputController, event->device->vendorID, event->device->productID, event->axisID, event->value, event->lastValue); } static bool gamepadAttach(Atom eventID, void * eventData, void * context) { Shell_redisplay(); return true; } static bool gamepadDetach(Atom eventID, void * eventData, void * context) { Shell_redisplay(); return true; } static bool actionDown(Atom eventID, void * eventData, void * context) { ControlsScreen * self = context; Atom actionID = eventData; if (actionID == ATOM("down")) { menuDown(self); return true; } if (actionID == ATOM("up")) { menuUp(self); return true; } if (actionID == ATOM("jump")) { menuAction(self); return true; } if (actionID == ATOM("action")) { menuBack(self); return true; } return false; } static const char * humanReadableKeyCode(unsigned int keyCode) { switch (keyCode) { case KEYBOARD_A: return "A"; case KEYBOARD_B: return "B"; case KEYBOARD_C: return "C"; case KEYBOARD_D: return "D"; case KEYBOARD_E: return "E"; case KEYBOARD_F: return "F"; case KEYBOARD_G: return "G"; case KEYBOARD_H: return "H"; case KEYBOARD_I: return "I"; case KEYBOARD_J: return "J"; case KEYBOARD_K: return "K"; case KEYBOARD_L: return "L"; case KEYBOARD_M: return "M"; case KEYBOARD_N: return "N"; case KEYBOARD_O: return "O"; case KEYBOARD_P: return "P"; case KEYBOARD_Q: return "Q"; case KEYBOARD_R: return "R"; case KEYBOARD_S: return "S"; case KEYBOARD_T: return "T"; case KEYBOARD_U: return "U"; case KEYBOARD_V: return "V"; case KEYBOARD_W: return "W"; case KEYBOARD_X: return "X"; case KEYBOARD_Y: return "Y"; case KEYBOARD_Z: return "Z"; case KEYBOARD_1: return "1"; case KEYBOARD_2: return "2"; case KEYBOARD_3: return "3"; case KEYBOARD_4: return "4"; case KEYBOARD_5: return "5"; case KEYBOARD_6: return "6"; case KEYBOARD_7: return "7"; case KEYBOARD_8: return "8"; case KEYBOARD_9: return "9"; case KEYBOARD_0: return "0"; case KEYBOARD_RETURN_OR_ENTER: return "Enter"; case KEYBOARD_ESCAPE: return "Esc"; case KEYBOARD_DELETE_OR_BACKSPACE: return "Backspace"; case KEYBOARD_TAB: return "Tab"; case KEYBOARD_SPACEBAR: return "Space"; case KEYBOARD_HYPHEN: return "-"; case KEYBOARD_EQUAL_SIGN: return "="; case KEYBOARD_OPEN_BRACKET: return "["; case KEYBOARD_CLOSE_BRACKET: return "]"; case KEYBOARD_BACKSLASH: return "\\"; case KEYBOARD_SEMICOLON: return ";"; case KEYBOARD_QUOTE: return "'"; case KEYBOARD_GRAVE_ACCENT_AND_TILDE: return "`"; case KEYBOARD_COMMA: return ","; case KEYBOARD_PERIOD: return "."; case KEYBOARD_SLASH: return "/"; case KEYBOARD_F1: return "F1"; case KEYBOARD_F2: return "F2"; case KEYBOARD_F3: return "F3"; case KEYBOARD_F4: return "F4"; case KEYBOARD_F5: return "F5"; case KEYBOARD_F6: return "F6"; case KEYBOARD_F7: return "F7"; case KEYBOARD_F8: return "F8"; case KEYBOARD_F9: return "F9"; case KEYBOARD_F10: return "F10"; case KEYBOARD_F11: return "F11"; case KEYBOARD_F12: return "F12"; case KEYBOARD_PRINT_SCREEN: return "Print Screen"; case KEYBOARD_SCROLL_LOCK: return "Scroll Lock"; case KEYBOARD_PAUSE: return "Pause"; case KEYBOARD_INSERT: return "Ins"; case KEYBOARD_HOME: return "Home"; case KEYBOARD_PAGE_UP: return "Pg Up"; case KEYBOARD_DELETE_FORWARD: return "Delete"; case KEYBOARD_END: return "End"; case KEYBOARD_PAGE_DOWN: return "Pg Dn"; case KEYBOARD_RIGHT_ARROW: return "Right Arrow"; case KEYBOARD_LEFT_ARROW: return "Left Arrow"; case KEYBOARD_DOWN_ARROW: return "Down Arrow"; case KEYBOARD_UP_ARROW: return "Up Arrow"; case KEYPAD_NUM_LOCK: return "Num Lock"; case KEYPAD_SLASH: return "Keypad /"; case KEYPAD_ASTERISK: return "Keypad *"; case KEYPAD_HYPHEN: return "Keypad -"; case KEYPAD_PLUS: return "Keypad +"; case KEYPAD_ENTER: return "Keypad Enter"; case KEYPAD_1: return "Keypad 1"; case KEYPAD_2: return "Keypad 2"; case KEYPAD_3: return "Keypad 3"; case KEYPAD_4: return "Keypad 4"; case KEYPAD_5: return "Keypad 5"; case KEYPAD_6: return "Keypad 6"; case KEYPAD_7: return "Keypad 7"; case KEYPAD_8: return "Keypad 8"; case KEYPAD_9: return "Keypad 9"; case KEYPAD_0: return "Keypad 0"; case KEYPAD_PERIOD: return "Keypad ."; case KEYPAD_EQUAL_SIGN: return "Keypad ="; default: return "[unknown]"; } } bool isGamepadConnected(int vendorID, int productID) { unsigned int deviceIndex; struct Gamepad_device * device; for (deviceIndex = 0; deviceIndex < Gamepad_numDevices(); deviceIndex++) { device = Gamepad_deviceAtIndex(deviceIndex); if (device->vendorID == vendorID && device->productID == productID) { return true; } } return false; } static void getControlString(ControlsScreen * self, char * outString, size_t maxLength, unsigned int menuItemIndex) { unsigned int gamepadIndex, bindingIndex; bool first = true; size_t length; outString[0] = 0; for (bindingIndex = 0; bindingIndex < self->gameSession->inputMap->keyboardBindingCount; bindingIndex++) { if (self->gameSession->inputMap->keyboardBindings[bindingIndex].actionID == actionIDs[menuItemIndex]) { length = strlen(outString); snprintf_safe(outString + length, maxLength - length, "%s%s", first ? "" : ", ", humanReadableKeyCode(self->gameSession->inputMap->keyboardBindings[bindingIndex].keyCode)); first = false; } } for (gamepadIndex = 0; gamepadIndex < self->gameSession->inputMap->gamepadMapCount; gamepadIndex++) { if (!isGamepadConnected(self->gameSession->inputMap->gamepadMaps[gamepadIndex].vendorID, self->gameSession->inputMap->gamepadMaps[gamepadIndex].productID)) { continue; } for (bindingIndex = 0; bindingIndex < self->gameSession->inputMap->gamepadMaps[gamepadIndex].buttonBindingCount; bindingIndex++) { if (self->gameSession->inputMap->gamepadMaps[gamepadIndex].buttonBindings[bindingIndex].actionID == actionIDs[menuItemIndex]) { length = strlen(outString); snprintf_safe(outString + length, maxLength - length, "%sButton %u", first ? "" : ", ", self->gameSession->inputMap->gamepadMaps[gamepadIndex].buttonBindings[bindingIndex].buttonID); first = false; } } for (bindingIndex = 0; bindingIndex < self->gameSession->inputMap->gamepadMaps[gamepadIndex].axisBindingCount; bindingIndex++) { if (self->gameSession->inputMap->gamepadMaps[gamepadIndex].axisBindings[bindingIndex].actionID == actionIDs[menuItemIndex]) { length = strlen(outString); snprintf_safe(outString + length, maxLength - length, "%sAxis %u %s", first ? "" : ", ", self->gameSession->inputMap->gamepadMaps[gamepadIndex].axisBindings[bindingIndex].axisID, self->gameSession->inputMap->gamepadMaps[gamepadIndex].axisBindings[bindingIndex].triggerThreshold < 0.0f ? "-" : "+"); first = false; } } } } #define CONTROL_STRING_MAX 128 #define ITEM_EM_HEIGHT 32 static void getMenuItemVertices(ControlsScreen * self, struct vertex_p2f_t2f_c4f * outVertices, GLushort * outIndexes, unsigned int * ioVertexCount, unsigned int * ioIndexCount) { Color4f colors[MENU_ITEM_COUNT]; unsigned int colorIndex, actionIDIndex; char controlString[CONTROL_STRING_MAX]; float leftWidth, rightWidth, maxRightWidth, originX; for (colorIndex = 0; colorIndex < MENU_ITEM_COUNT; colorIndex++) { if (colorIndex == self->menuItemIndex) { if (self->waitingForInput) { colors[colorIndex] = MENU_COLOR_SELECTED; } else { colors[colorIndex] = MENU_COLOR_HIGHLIGHTED; } } else { colors[colorIndex] = MENU_COLOR_ENABLED; } } leftWidth = GLBitmapFont_measureString(self->bitmapFont, "Action: ", GLBITMAPFONT_USE_STRLEN) * ITEM_EM_HEIGHT; maxRightWidth = 0.0f; for (actionIDIndex = 0; actionIDIndex < MENU_ITEM_COUNT - 1; actionIDIndex++) { getControlString(self, controlString, CONTROL_STRING_MAX, actionIDIndex); rightWidth = GLBitmapFont_measureString(self->bitmapFont, controlString, GLBITMAPFONT_USE_STRLEN) * ITEM_EM_HEIGHT; if (rightWidth > maxRightWidth) { maxRightWidth = rightWidth; } } if (maxRightWidth + leftWidth > 640.0f) { maxRightWidth = 640.0f - leftWidth; } originX = (640.0f - (leftWidth + maxRightWidth)) / 2 + leftWidth; GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "Left: ", GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(originX, 198.0f), VECTOR2f(1.0f, 0.5f), colors[MENU_ITEM_LEFT], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "Right: ", GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(originX, 230.0f), VECTOR2f(1.0f, 0.5f), colors[MENU_ITEM_RIGHT], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "Down: ", GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(originX, 262.0f), VECTOR2f(1.0f, 0.5f), colors[MENU_ITEM_DOWN], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "Up: ", GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(originX, 294.0f), VECTOR2f(1.0f, 0.5f), colors[MENU_ITEM_UP], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "Jump: ", GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(originX, 326.0f), VECTOR2f(1.0f, 0.5f), colors[MENU_ITEM_JUMP], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "Action: ", GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(originX, 358.0f), VECTOR2f(1.0f, 0.5f), colors[MENU_ITEM_ACTION], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "Pause: ", GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(originX, 390.0f), VECTOR2f(1.0f, 0.5f), colors[MENU_ITEM_PAUSE], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "DONE", GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(320.0f, 454.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_DONE], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); for (actionIDIndex = 0; actionIDIndex < MENU_ITEM_COUNT - 1; actionIDIndex++) { getControlString(self, controlString, CONTROL_STRING_MAX, actionIDIndex); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, controlString, GLBITMAPFONT_USE_STRLEN, -ITEM_EM_HEIGHT, VECTOR2f(originX, 198.0f + 32.0f * actionIDIndex), VECTOR2f(0.0f, 0.5f), colors[actionIDIndex], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); } } static bool draw(Atom eventID, void * eventData, void * context) { ControlsScreen * self = context; struct vertex_p2f_t2f_c4f * vertices; GLushort * indexes; unsigned int vertexCount, indexCount; glClearColor(1.0f, 1.0f, 1.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glOrtho(0.0f, 640.0f, 480.0f, 0.0f, -1.0f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glBindBufferARB(GL_ARRAY_BUFFER, self->vertexBufferID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, self->indexBufferID); vertexCount = indexCount = 0; getMenuItemVertices(self, NULL, NULL, &vertexCount, &indexCount); glBufferDataARB(GL_ARRAY_BUFFER, sizeof(struct vertex_p2f_t2f_c4f) * vertexCount, NULL, GL_STREAM_DRAW); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indexCount, NULL, GL_STREAM_DRAW); vertices = glMapBufferARB(GL_ARRAY_BUFFER, GL_WRITE_ONLY); indexes = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); vertexCount = indexCount = 0; getMenuItemVertices(self, vertices, indexes, &vertexCount, &indexCount); glUnmapBufferARB(GL_ARRAY_BUFFER); glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER); glVertexPointer(2, GL_FLOAT, sizeof(struct vertex_p2f_t2f_c4f), (void *) offsetof(struct vertex_p2f_t2f_c4f, position)); glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex_p2f_t2f_c4f), (void *) offsetof(struct vertex_p2f_t2f_c4f, texCoords)); glColorPointer(4, GL_FLOAT, sizeof(struct vertex_p2f_t2f_c4f), (void *) offsetof(struct vertex_p2f_t2f_c4f, color)); GLTexture_activate(self->bitmapFont->atlas->texture); glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0); GLTexture_deactivate(self->bitmapFont->atlas->texture); glBindBufferARB(GL_ARRAY_BUFFER, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); return true; } static bool confirmQuit(Atom eventID, void * eventData, void * context) { ControlsScreen * self = context; if (self->gameSession->testingLevel && self->gameSession-> viewingSettingsFromGameplay && self->gameSession->hasUnsavedLevelChanges) { GameSession_saveControlBindings(self->gameSession); ScreenManager_transition(self->screenManager, "back"); return true; } return false; } void ControlsScreen_activate(ControlsScreen * self) { EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_MOUSE_DOWN), mouseDown, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_KEY_DOWN), keyDown, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_KEY_UP), keyUp, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_BUTTON_DOWN), gamepadButtonDown, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_BUTTON_UP), gamepadButtonUp, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_AXIS_MOVE), gamepadAxisMove, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_ATTACH), gamepadAttach, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_DETACH), gamepadDetach, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_DRAW), draw, self); EventDispatcher_registerForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_CONFIRM_QUIT), confirmQuit, self); EventDispatcher_registerForEvent(self->inputController->eventDispatcher, ATOM(INPUT_CONTROLLER_EVENT_ACTION_DOWN), actionDown, self); Shell_redisplay(); Shell_setCursorVisible(true); } void ControlsScreen_deactivate(ControlsScreen * self) { EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_MOUSE_DOWN), mouseDown, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_KEY_DOWN), keyDown, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_KEY_UP), keyUp, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_BUTTON_DOWN), gamepadButtonDown, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_BUTTON_UP), gamepadButtonUp, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_AXIS_MOVE), gamepadAxisMove, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_ATTACH), gamepadAttach, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_GAMEPAD_DETACH), gamepadDetach, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_DRAW), draw, self); EventDispatcher_unregisterForEvent(self->screenManager->eventDispatcher, ATOM(EVENT_CONFIRM_QUIT), confirmQuit, self); EventDispatcher_unregisterForEvent(self->inputController->eventDispatcher, ATOM(INPUT_CONTROLLER_EVENT_ACTION_DOWN), actionDown, self); }