// 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/ManageLevelsScreen.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 #define EM_HEIGHT_SMALL 16 #define EM_HEIGHT_LARGE 32 #define CONFIRM_DELETE_STRING_PREFIX "Confirm delete? " #define CONFIRM_DELETE_STRING_YES "YES" #define CONFIRM_DELETE_STRING_SEPARATOR " | " #define CONFIRM_DELETE_STRING_NO "NO" #define CONFIRM_DELETE_STRING CONFIRM_DELETE_STRING_PREFIX CONFIRM_DELETE_STRING_YES CONFIRM_DELETE_STRING_SEPARATOR CONFIRM_DELETE_STRING_NO enum { MENU_ITEM_NEW, MENU_ITEM_EDIT, MENU_ITEM_DELETE, MENU_ITEM_RENAME, MENU_ITEM_DUPLICATE, MENU_ITEM_IMPORT, MENU_ITEM_EXPORT, MENU_ITEM_DONE, MENU_ITEM_COUNT }; ManageLevelsScreen * ManageLevelsScreen_create(GameSession * gameSession) { stemobject_create_implementation(ManageLevelsScreen, init, gameSession) } bool ManageLevelsScreen_init(ManageLevelsScreen * self, GameSession * gameSession) { call_super(init, self); self->activate = ManageLevelsScreen_activate; self->deactivate = ManageLevelsScreen_deactivate; self->dispose = ManageLevelsScreen_dispose; self->gameSession = gameSession; self->inputController = InputController_create(gameSession->inputMap, "left", "right", "down", "up", "jump", "action", "pause", NULL); self->menuItemIndex = 0; self->selectingLevelSet = false; self->editingLevelSetName = false; self->confirmingDelete = false; self->errorText[0] = 0; glGenBuffersARB(1, &self->vertexBufferID); glGenBuffersARB(1, &self->indexBufferID); self->bitmapFont = ResourceManager_referenceResource(self->gameSession->resourceManager, "bitmap_font", "pixelfont.json"); return true; } void ManageLevelsScreen_dispose(ManageLevelsScreen * 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 bool isMenuItemEnabled(ManageLevelsScreen * self, unsigned int menuItemIndex) { if (self->selectingLevelSet) { return false; } switch (menuItemIndex) { case MENU_ITEM_NEW: case MENU_ITEM_IMPORT: case MENU_ITEM_DUPLICATE: return self->gameSession->levelSetCount < LEVEL_SET_COUNT_MAX; case MENU_ITEM_EXPORT: case MENU_ITEM_RENAME: case MENU_ITEM_DELETE: case MENU_ITEM_EDIT: return self->gameSession->levelSetCount > BUILT_IN_LEVEL_SET_COUNT; case MENU_ITEM_DONE: default: return true; } } static bool isLevelSetEnabled(ManageLevelsScreen * self, unsigned int levelSetIndex) { if (!self->selectingLevelSet) { return false; } if (levelSetIndex >= BUILT_IN_LEVEL_SET_COUNT) { return true; } return self->menuItemIndex == MENU_ITEM_DUPLICATE; } static void menuLeft(ManageLevelsScreen * self) { if (self->confirmingDelete) { self->deleteConfirmed = !self->deleteConfirmed; Shell_redisplay(); } } static void menuRight(ManageLevelsScreen * self) { if (self->confirmingDelete) { self->deleteConfirmed = !self->deleteConfirmed; Shell_redisplay(); } } static void menuDown(ManageLevelsScreen * self) { if (self->editingLevelSetName || self->confirmingDelete) { return; } if (self->selectingLevelSet) { do { self->levelSetIndex += 1; self->levelSetIndex %= self->gameSession->levelSetCount + 1; } while (!isLevelSetEnabled(self, self->levelSetIndex)); } else { do { self->menuItemIndex += 1; self->menuItemIndex %= MENU_ITEM_COUNT; } while (!isMenuItemEnabled(self, self->menuItemIndex)); } Shell_redisplay(); } static void menuUp(ManageLevelsScreen * self) { if (self->editingLevelSetName || self->confirmingDelete) { return; } if (self->selectingLevelSet) { do { self->levelSetIndex += self->gameSession->levelSetCount; self->levelSetIndex %= self->gameSession->levelSetCount + 1; } while (!isLevelSetEnabled(self, self->levelSetIndex)); } else { do { self->menuItemIndex += MENU_ITEM_COUNT - 1; self->menuItemIndex %= MENU_ITEM_COUNT; } while (!isMenuItemEnabled(self, self->menuItemIndex)); } Shell_redisplay(); } static void menuAction(ManageLevelsScreen * self, unsigned int menuItemIndex) { if (!isMenuItemEnabled(self, menuItemIndex)) { return; } self->menuItemIndex = menuItemIndex; switch (menuItemIndex) { case MENU_ITEM_NEW: { LevelSetModel * newLevelSet; newLevelSet = LevelSetModel_create("untitled.lvl"); newLevelSet->levelCount = 1; newLevelSet->levels = malloc(sizeof(LevelModel *)); newLevelSet->levels[0] = LevelModel_create(); GameSession_addLevelSet(self->gameSession, newLevelSet); if (!isMenuItemEnabled(self, self->menuItemIndex)) { menuDown(self); } Shell_redisplay(); break; } case MENU_ITEM_IMPORT: { bool success; char filePath[4096]; success = Shell_openFileDialog(NULL, filePath, 4096); if (success) { LevelSetModel * levelSet; levelSet = LevelFileIO_createLevelSetFromFile(filePath, NULL); if (levelSet == NULL) { Shell_systemBeep(); snprintf_safe(self->errorText, MANAGE_LEVELS_ERROR_TEXT_LENGTH, "Error: Couldn't load %s as a level file", filePath); } else { self->errorText[0] = 0; GameSession_addLevelSet(self->gameSession, levelSet); if (!isMenuItemEnabled(self, self->menuItemIndex)) { menuDown(self); } } } Shell_redisplay(); InputController_releaseAction(self->inputController, ATOM("jump")); break; } case MENU_ITEM_EXPORT: case MENU_ITEM_RENAME: case MENU_ITEM_EDIT: case MENU_ITEM_DELETE: if (self->levelSetIndex >= self->gameSession->levelSetCount || self->levelSetIndex < BUILT_IN_LEVEL_SET_COUNT) { self->levelSetIndex = BUILT_IN_LEVEL_SET_COUNT; } self->selectingLevelSet = true; self->errorText[0] = 0; Shell_redisplay(); break; case MENU_ITEM_DUPLICATE: if (self->levelSetIndex >= self->gameSession->levelSetCount) { self->levelSetIndex = 0; } self->selectingLevelSet = true; self->errorText[0] = 0; Shell_redisplay(); break; case MENU_ITEM_DONE: self->errorText[0] = 0; InputController_reset(self->inputController); ScreenManager_transition(self->screenManager, "back"); break; } } static void menuBack(ManageLevelsScreen * self) { if (self->selectingLevelSet) { self->confirmingDelete = false; self->editingLevelSetName = false; self->selectingLevelSet = false; Shell_redisplay(); } else { menuAction(self, MENU_ITEM_DONE); } } static void levelSetAction(ManageLevelsScreen * self, unsigned int levelSetIndex) { if (levelSetIndex > self->gameSession->levelSetCount) { return; } if (levelSetIndex == self->gameSession->levelSetCount) { self->selectingLevelSet = false; Shell_redisplay(); return; } self->levelSetIndex = levelSetIndex; switch (self->menuItemIndex) { case MENU_ITEM_EXPORT: { bool success; char filePath[4096]; success = Shell_saveFileDialog(NULL, self->gameSession->levelSets[self->levelSetIndex]->name, filePath, 4096); if (success) { success = LevelFileIO_writeLevelSetToFile(self->gameSession->levelSets[self->levelSetIndex], filePath); if (!success) { Shell_systemBeep(); snprintf_safe(self->errorText, MANAGE_LEVELS_ERROR_TEXT_LENGTH, "Error: Couldn't save %s to %s", self->gameSession->levelSets[self->levelSetIndex]->name, filePath); } } self->selectingLevelSet = false; InputController_releaseAction(self->inputController, ATOM("jump")); Shell_redisplay(); break; } case MENU_ITEM_RENAME: if (self->editingLevelSetName) { if (strlen(self->nameText) > 0) { free(self->gameSession->levelSets[self->levelSetIndex]->name); self->gameSession->levelSets[self->levelSetIndex]->name = strdup(self->nameText); GameSession_levelSetNameUpdated(self->gameSession, self->levelSetIndex); } self->editingLevelSetName = false; self->selectingLevelSet = false; } else { strncpy_safe(self->nameText, self->gameSession->levelSets[self->levelSetIndex]->name, LEVEL_SET_NAME_MAX); self->editingLevelSetName = true; } Shell_redisplay(); break; case MENU_ITEM_DUPLICATE: GameSession_addLevelSet(self->gameSession, LevelSetModel_copy(self->gameSession->levelSets[self->levelSetIndex])); self->selectingLevelSet = false; if (!isMenuItemEnabled(self, self->menuItemIndex)) { menuDown(self); } Shell_redisplay(); break; case MENU_ITEM_EDIT: self->errorText[0] = 0; self->gameSession->selectedLevelSetIndex = self->levelSetIndex; InputController_reset(self->inputController); ScreenManager_transition(self->screenManager, "edit_level"); break; case MENU_ITEM_DELETE: self->deleteConfirmed = false; self->confirmingDelete = true; Shell_redisplay(); break; } } static void confirmDeleteAction(ManageLevelsScreen * self) { if (self->deleteConfirmed) { GameSession_deleteLevelSet(self->gameSession, self->levelSetIndex); } self->confirmingDelete = false; self->selectingLevelSet = false; while (!isMenuItemEnabled(self, self->menuItemIndex)) { self->menuItemIndex += 1; self->menuItemIndex %= MENU_ITEM_COUNT; } Shell_redisplay(); } static bool mouseDown(Atom eventID, void * eventData, void * context) { struct mouseEvent * event = eventData; ManageLevelsScreen * self = context; if (self->selectingLevelSet) { if (self->confirmingDelete) { if (event->position.y >= 12.0f + EM_HEIGHT_SMALL * self->gameSession->levelSetCount && event->position.y <= 12.0f + EM_HEIGHT_SMALL * (self->gameSession->levelSetCount + 1)) { float yesLeft, yesRight, noLeft, noRight, positionX; positionX = 480.0f - GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL / 2; positionX += GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING_PREFIX, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL; yesLeft = positionX; positionX += GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING_YES, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL; yesRight = positionX; positionX += GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING_SEPARATOR, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL; noLeft = positionX; positionX += GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING_NO, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL; noRight = positionX; if (event->position.x >= yesLeft && event->position.x <= yesRight) { self->deleteConfirmed = true; confirmDeleteAction(self); } else if (event->position.x >= noLeft && event->position.x <= noRight) { self->deleteConfirmed = false; confirmDeleteAction(self); } } } else if (event->position.x < 360.0f) { levelSetAction(self, self->gameSession->levelSetCount); } else { if (event->position.y >= 4.0f) { if (event->position.y >= 12.0f + EM_HEIGHT_SMALL * self->gameSession->levelSetCount && event->position.y <= 12.0f + EM_HEIGHT_SMALL * (self->gameSession->levelSetCount + 1)) { levelSetAction(self, self->gameSession->levelSetCount); } else if (event->position.y < 4.0f + EM_HEIGHT_SMALL * self->gameSession->levelSetCount) { levelSetAction(self, (event->position.y - 4.0f) / EM_HEIGHT_SMALL); } } } } else { if (event->position.x < 360.0f && event->position.y >= 112.0f) { menuAction(self, (event->position.y - 112.0f) / EM_HEIGHT_LARGE); } } return false; } static bool keyDown(Atom eventID, void * eventData, void * context) { struct keyEvent * event = eventData; ManageLevelsScreen * self = context; if (!self->editingLevelSetName && event->isRepeat) { return false; } switch (event->keyCode) { case KEYBOARD_ESCAPE: menuBack(self); return true; case KEYBOARD_RETURN_OR_ENTER: InputController_triggerAction(self->inputController, ATOM("jump")); return true; case KEYBOARD_LEFT_ARROW: InputController_triggerAction(self->inputController, ATOM("left")); return true; case KEYBOARD_RIGHT_ARROW: InputController_triggerAction(self->inputController, ATOM("right")); 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; case KEYBOARD_DELETE_OR_BACKSPACE: if (self->editingLevelSetName && self->nameText[0] != 0) { self->nameText[strlen(self->nameText) - 1] = 0; Shell_redisplay(); } break; case KEYBOARD_SPACEBAR: if (!self->editingLevelSetName) { InputController_triggerAction(self->inputController, ATOM("jump")); return true; } default: if (self->editingLevelSetName && event->charCode >= GLBITMAPFONT_PRINTABLE_MIN && event->charCode <= GLBITMAPFONT_PRINTABLE_MAX) { size_t length = strlen(self->nameText); if (length < LEVEL_SET_NAME_MAX - 1) { self->nameText[length] = event->charCode; self->nameText[length + 1] = 0; Shell_redisplay(); } } break; } if (!self->editingLevelSetName) { return InputController_keyDown(self->inputController, event->keyCode); } return false; } static bool keyUp(Atom eventID, void * eventData, void * context) { struct keyEvent * event = eventData; ManageLevelsScreen * self = context; switch (event->keyCode) { case KEYBOARD_RETURN_OR_ENTER: InputController_releaseAction(self->inputController, ATOM("jump")); return true; case KEYBOARD_LEFT_ARROW: InputController_releaseAction(self->inputController, ATOM("left")); return true; case KEYBOARD_RIGHT_ARROW: InputController_releaseAction(self->inputController, ATOM("right")); 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; case KEYBOARD_SPACEBAR: if (!self->editingLevelSetName) { InputController_releaseAction(self->inputController, ATOM("jump")); return true; } break; } return InputController_keyUp(self->inputController, event->keyCode); } static bool gamepadButtonDown(Atom eventID, void * eventData, void * context) { struct gamepadButtonEvent * event = eventData; ManageLevelsScreen * self = context; 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; ManageLevelsScreen * self = context; return InputController_gamepadButtonUp(self->inputController, event->device->vendorID, event->device->productID, event->buttonID); } static bool gamepadAxisMove(Atom eventID, void * eventData, void * context) { struct gamepadAxisEvent * event = eventData; ManageLevelsScreen * self = context; return InputController_gamepadAxisMoved(self->inputController, event->device->vendorID, event->device->productID, event->axisID, event->value, event->lastValue); } static bool actionDown(Atom eventID, void * eventData, void * context) { ManageLevelsScreen * self = context; Atom actionID = eventData; if (actionID == ATOM("left")) { menuLeft(self); return true; } if (actionID == ATOM("right")) { menuRight(self); return true; } if (actionID == ATOM("down")) { menuDown(self); return true; } if (actionID == ATOM("up")) { menuUp(self); return true; } if (actionID == ATOM("jump")) { if (self->selectingLevelSet) { if (self->confirmingDelete) { confirmDeleteAction(self); } else { levelSetAction(self, self->levelSetIndex); } } else { menuAction(self, self->menuItemIndex); } return true; } if (actionID == ATOM("action")) { menuBack(self); return true; } return false; } #define ITEM_STRING_MAX 32 static void getMenuItemVertices(ManageLevelsScreen * self, struct vertex_p2f_t2f_c4f * outVertices, GLushort * outIndexes, unsigned int * ioVertexCount, unsigned int * ioIndexCount) { Color4f colors[MENU_ITEM_COUNT]; unsigned int colorIndex; unsigned int levelSetIndex; Color4f levelSetColor; const char * levelSetName; for (colorIndex = 0; colorIndex < MENU_ITEM_COUNT; colorIndex++) { if (colorIndex == self->menuItemIndex) { if (self->selectingLevelSet) { colors[colorIndex] = MENU_COLOR_SELECTED; } else { colors[colorIndex] = MENU_COLOR_HIGHLIGHTED; } } else if (!isMenuItemEnabled(self, colorIndex)) { colors[colorIndex] = MENU_COLOR_DISABLED; } else { colors[colorIndex] = MENU_COLOR_ENABLED; } } GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "NEW", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_LARGE, VECTOR2f(160.0f, 128.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_NEW], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "EDIT", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_LARGE, VECTOR2f(160.0f, 160.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_EDIT], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "DELETE", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_LARGE, VECTOR2f(160.0f, 192.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_DELETE], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "RENAME", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_LARGE, VECTOR2f(160.0f, 224.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_RENAME], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "DUPLICATE", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_LARGE, VECTOR2f(160.0f, 256.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_DUPLICATE], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "IMPORT", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_LARGE, VECTOR2f(160.0f, 288.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_IMPORT], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "EXPORT", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_LARGE, VECTOR2f(160.0f, 320.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_EXPORT], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "DONE", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_LARGE, VECTOR2f(160.0f, 352.0f), VECTOR2f(0.5f, 0.5f), colors[MENU_ITEM_DONE], GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); for (levelSetIndex = 0; levelSetIndex < self->gameSession->levelSetCount; levelSetIndex++) { levelSetName = self->gameSession->levelSets[levelSetIndex]->name; if (self->selectingLevelSet && levelSetIndex == self->levelSetIndex) { if (self->confirmingDelete) { levelSetColor = MENU_COLOR_SELECTED; } else if (self->editingLevelSetName) { levelSetName = self->nameText; levelSetColor = MENU_COLOR_SELECTED; } else { levelSetColor = MENU_COLOR_HIGHLIGHTED; } } else if (!isLevelSetEnabled(self, levelSetIndex)) { levelSetColor = MENU_COLOR_DISABLED; } else { levelSetColor = MENU_COLOR_ENABLED; } GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, levelSetName, GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_SMALL, VECTOR2f(480.0f, 4.0f + EM_HEIGHT_SMALL * levelSetIndex), VECTOR2f(0.5f, 1.0f), levelSetColor, GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); } if (self->selectingLevelSet && !self->editingLevelSetName) { if (self->confirmingDelete) { float positionX; positionX = 480.0f - GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL / 2; GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, CONFIRM_DELETE_STRING_PREFIX, GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_SMALL, VECTOR2f(positionX, EM_HEIGHT_SMALL + EM_HEIGHT_SMALL * levelSetIndex), VECTOR2f(0.0f, 1.0f), MENU_COLOR_NONINTERACTIVE, GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); positionX += GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING_PREFIX, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL; GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, CONFIRM_DELETE_STRING_YES, GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_SMALL, VECTOR2f(positionX, EM_HEIGHT_SMALL + EM_HEIGHT_SMALL * levelSetIndex), VECTOR2f(0.0f, 1.0f), self->deleteConfirmed ? MENU_COLOR_HIGHLIGHTED : MENU_COLOR_ENABLED, GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); positionX += GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING_YES, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL; GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, CONFIRM_DELETE_STRING_SEPARATOR, GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_SMALL, VECTOR2f(positionX, EM_HEIGHT_SMALL + EM_HEIGHT_SMALL * levelSetIndex), VECTOR2f(0.0f, 1.0f), MENU_COLOR_NONINTERACTIVE, GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); positionX += GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING_SEPARATOR, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL; GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, CONFIRM_DELETE_STRING_NO, GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_SMALL, VECTOR2f(positionX, EM_HEIGHT_SMALL + EM_HEIGHT_SMALL * levelSetIndex), VECTOR2f(0.0f, 1.0f), self->deleteConfirmed ? MENU_COLOR_ENABLED : MENU_COLOR_HIGHLIGHTED, GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); positionX += GLBitmapFont_measureString(self->bitmapFont, CONFIRM_DELETE_STRING_NO, GLBITMAPFONT_USE_STRLEN) * EM_HEIGHT_SMALL; } else { if (self->levelSetIndex == self->gameSession->levelSetCount) { levelSetColor = MENU_COLOR_HIGHLIGHTED; } else { levelSetColor = MENU_COLOR_ENABLED; } GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, "CANCEL", GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_SMALL, VECTOR2f(480.0f, EM_HEIGHT_SMALL + EM_HEIGHT_SMALL * levelSetIndex), VECTOR2f(0.5f, 1.0f), levelSetColor, GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); } } GLBitmapFont_getStringVerticesWithColor(self->bitmapFont, self->errorText, GLBITMAPFONT_USE_STRLEN, -EM_HEIGHT_SMALL, VECTOR2f(4.0f, 476.0f), VECTOR2f(0.0f, 0.0f), MENU_COLOR_ERROR, GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); } static bool draw(Atom eventID, void * eventData, void * context) { ManageLevelsScreen * 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; } void ManageLevelsScreen_activate(ManageLevelsScreen * 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_DRAW), draw, self); EventDispatcher_registerForEvent(self->inputController->eventDispatcher, ATOM(INPUT_CONTROLLER_EVENT_ACTION_DOWN), actionDown, self); self->selectingLevelSet = false; Shell_redisplay(); Shell_setCursorVisible(true); } void ManageLevelsScreen_deactivate(ManageLevelsScreen * 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_DRAW), draw, self); EventDispatcher_unregisterForEvent(self->inputController->eventDispatcher, ATOM(INPUT_CONTROLLER_EVENT_ACTION_DOWN), actionDown, self); }