diff --git a/apps/2048.cpp b/apps/2048.cpp new file mode 100644 index 0000000..dab8133 --- /dev/null +++ b/apps/2048.cpp @@ -0,0 +1,384 @@ +#include +#include + +// TODO Application icon. + +#define TILE_COUNT (4) +#define TILE_SIZE ((int32_t) (75 * scale)) +#define TILE_GAP ((int32_t) (10 * scale)) +#define CELL_FILL (0xFFEEEEEE) +#define TILE_TEXT_COLOR (0xFFFFFF) +#define TILE_TEXT_GLOW (0x000000) +#define MAIN_AREA_SIZE() (TILE_SIZE * TILE_COUNT + TILE_GAP * (TILE_COUNT + 1)) +#define MAIN_AREA_FILL (0xFFFFFFFF) +#define MAIN_AREA_BORDER (0xFFCCCCCC) +#define ANIMATION_TIME (100) + +#define TILE_BOUNDS(x, y) ES_RECT_4PD(mainArea.l + TILE_GAP * (x + 1) + TILE_SIZE * x, mainArea.t + TILE_GAP * (y + 1) + TILE_SIZE * y, TILE_SIZE, TILE_SIZE) + +#define SETTINGS_FILE "|Settings:/Default.ini" + +struct AnimatingTile { + float sourceOpacity, targetOpacity; + uint8_t sourceX, targetX; + uint8_t sourceY, targetY; + uint8_t sourceNumber; +}; + +const uint32_t tileColors[] = { + 0x000000, 0x7CB5E2, 0x4495D4, 0x2F6895, + 0xF5BD70, 0xF2A032, 0xE48709, 0xE37051, + 0xDE5833, 0xBD4A2B, 0x5454DA, 0x3B3C99, + 0xFFD700, +}; + +const uint32_t tileTextSizes[] = { + 0, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 16, 16, 16, 16, 14, 14, + 14, 12, 12, 12, 10, 10, 10, 10, + 8, 8, 8, 6, 6, 6, 6, 6, +}; + +AnimatingTile animatingTiles[TILE_COUNT * TILE_COUNT + 1]; +size_t animatingTileCount; +float animationTimeMs; + +uint8_t grid[TILE_COUNT][TILE_COUNT]; +uintptr_t currentTileCount; +int32_t score, highScore; + +EsInstance *instance; +EsElement *gameArea; +EsTextDisplay *scoreDisplay, *highScoreDisplay; + +void SaveConfiguration() { + EsBuffer buffer = {}; + buffer.canGrow = true; + EsBufferFormat(&buffer, "high_score=%d\n", highScore); + EsFileWriteAll(EsLiteral(SETTINGS_FILE), buffer.out, buffer.position); + EsHeapFree(buffer.out); +} + +bool MoveTiles(intptr_t dx, intptr_t dy, bool speculative) { + uint8_t undo[TILE_COUNT][TILE_COUNT]; + EsMemoryCopy(undo, grid, sizeof(undo)); + + bool validMove = false; + + for (uintptr_t p = 0; p < TILE_COUNT; p++) { + bool doneMerge = false; + + for (uintptr_t q = 0; q < TILE_COUNT; q++) { + // The tile being moved. + intptr_t x = dx ? q : p; + intptr_t y = dx ? p : q; + if (dx > 0) x = TILE_COUNT - 1 - x; + if (dy > 0) y = TILE_COUNT - 1 - y; + + // Ignore empty spaces. + if (!grid[x][y]) continue; + + // Setup the animation. + if (!speculative) { + AnimatingTile *animation = &animatingTiles[animatingTileCount]; + animation->sourceOpacity = 1; + animation->targetOpacity = 1; + animation->sourceX = x; + animation->sourceY = y; + animation->sourceNumber = grid[x][y]; + } + + while (true) { + // The position to move the tile to. + intptr_t nx = x + dx; + intptr_t ny = y + dy; + + // If the next position is outside the grid, stop. + if (nx < 0 || nx >= TILE_COUNT) break; + if (ny < 0 || ny >= TILE_COUNT) break; + + if (grid[nx][ny]) { + // If tiles are different, we can't merge; stop. + if (grid[nx][ny] != grid[x][y]) break; + + // If there's already been a merge this band, stop. + if (doneMerge) break; + + // Merge the tiles. + grid[nx][ny]++; + grid[x][y] = 0; + doneMerge = true; + + // Add the score. + if (!speculative) score += 1 << grid[nx][ny]; + } else { + // Slide the tile. + grid[nx][ny] = grid[x][y]; + grid[x][y] = 0; + } + + // Update the position. + x = nx; + y = ny; + validMove = true; + } + + // Set the animation target. + if (!speculative) { + AnimatingTile *animation = &animatingTiles[animatingTileCount]; + animation->targetX = x; + animation->targetY = y; + animatingTileCount++; + } + } + } + + if (speculative) { + EsMemoryCopy(grid, undo, sizeof(undo)); + } + + return validMove; +} + +void SpawnTile() { + if (currentTileCount == TILE_COUNT * TILE_COUNT) { + // The grid is full. + return; + } + + while (true) { + uintptr_t x = EsRandomU64() % TILE_COUNT; + uintptr_t y = EsRandomU64() % TILE_COUNT; + + if (!grid[x][y]) { + grid[x][y] = EsRandomU8() < 25 ? 2 : 1; + + // Setup the animation. + AnimatingTile *animation = &animatingTiles[animatingTileCount]; + animation->sourceOpacity = 0; + animation->targetOpacity = 1; + animation->sourceX = x; + animation->targetX = x; + animation->sourceY = y; + animation->targetY = y; + animation->sourceNumber = grid[x][y]; + animatingTileCount++; + + break; + } + } + + if (!MoveTiles(-1, 0, true) && !MoveTiles(1, 0, true) && !MoveTiles(0, -1, true) && !MoveTiles(0, 1, true)) { + // No moves are possible. + if (highScore < score) { + EsDialogShowAlert(instance->window, INTERFACE_STRING(Game2048GameOver), INTERFACE_STRING(Game2048NewHighScore), + ES_ICON_DIALOG_INFORMATION, ES_DIALOG_ALERT_OK_BUTTON); + } else { + EsDialogShowAlert(instance->window, INTERFACE_STRING(Game2048GameOver), INTERFACE_STRING(Game2048GameOverExplanation), + ES_ICON_DIALOG_INFORMATION, ES_DIALOG_ALERT_OK_BUTTON); + } + } +} + +void Update(intptr_t dx, intptr_t dy) { + animatingTileCount = 0; + animationTimeMs = 0; + + if (dx || dy) { + if (!MoveTiles(dx, dy, false)) { + return; + } + } + + SpawnTile(); + EsElementStartAnimating(gameArea); + + if (score > highScore) { + highScore = score; + } + + char buffer[64]; + size_t bytes = EsStringFormat(buffer, sizeof(buffer), "%d", score); + EsTextDisplaySetContents(scoreDisplay, buffer, bytes); + bytes = EsStringFormat(buffer, sizeof(buffer), interfaceString_Game2048HighScore, highScore); + EsTextDisplaySetContents(highScoreDisplay, buffer, bytes); +} + +void DrawTileText(EsPainter *painter, EsElement *element, EsRectangle bounds, float opacity, uint8_t number) { + char buffer[64]; + size_t bytes = EsStringFormat(buffer, sizeof(buffer), "%d", 1 << (uint32_t) number); + uint32_t alpha = ((uint32_t) (255 * opacity) << 24); + EsTextStyle style = { .font = { .family = ES_FONT_SANS, .weight = ES_FONT_SEMIBOLD }, .size = (uint16_t) tileTextSizes[number] }; + + if (number >= 12) { + style.color = TILE_TEXT_GLOW | alpha; + style.blur = 3; + EsDrawTextSimple(painter, element, bounds, buffer, bytes, style, ES_TEXT_H_CENTER | ES_TEXT_V_CENTER); + } + + style.color = TILE_TEXT_COLOR | alpha; + style.blur = 0; + EsDrawTextSimple(painter, element, bounds, buffer, bytes, style, ES_TEXT_H_CENTER | ES_TEXT_V_CENTER); +} + +void DrawTile(EsPainter *painter, EsElement *element, uint8_t sourceNumber, uint8_t targetNumber, + EsRectangle bounds, float opacity, const uint32_t *cornerRadii, float progress) { + size_t tileColorCount = sizeof(tileColors) / sizeof(tileColors[0]); + uint32_t sourceColor = sourceNumber >= tileColorCount ? tileColors[tileColorCount - 1] : tileColors[sourceNumber]; + uint32_t targetColor = targetNumber >= tileColorCount ? tileColors[tileColorCount - 1] : tileColors[targetNumber]; + uint32_t fill = EsColorInterpolate(sourceColor, targetColor, progress) | ((uint32_t) (255 * opacity) << 24); + float scale = EsElementGetScaleFactor(element); + + EsDrawRoundedRectangle(painter, bounds, fill, EsColorBlend(fill, 0x20000000, true), ES_RECT_4(0, 0, 0, 3 * scale), cornerRadii); + + if (sourceNumber == targetNumber) { + progress = 1.0f; + } + + DrawTileText(painter, element, bounds, progress, targetNumber); + + if (sourceNumber != targetNumber && targetNumber) { + DrawTileText(painter, element, bounds, 1.0f - progress, sourceNumber); + } +} + +int GameAreaMessage(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_PAINT) { + EsPainter *painter = message->painter; + float scale = EsElementGetScaleFactor(element); + + const uint32_t cornerRadii[4] = { (uint32_t) (3 * scale), (uint32_t) (3 * scale), (uint32_t) (3 * scale), (uint32_t) (3 * scale) }; + + EsRectangle bounds = EsPainterBoundsInset(painter); + EsRectangle mainArea = EsRectangleFit(bounds, ES_RECT_1S(MAIN_AREA_SIZE()), false); + EsDrawRoundedRectangle(painter, mainArea, MAIN_AREA_FILL, MAIN_AREA_BORDER, ES_RECT_1(scale * 1), cornerRadii); + + float progress = animationTimeMs / ANIMATION_TIME; + bool animationComplete = progress == 1.0; + + progress -= 1.0; + progress = 1 + progress * progress * progress; + + for (uintptr_t j = 0; j < TILE_COUNT; j++) { + for (uintptr_t i = 0; i < TILE_COUNT; i++) { + if (grid[i][j] && animationComplete) { + DrawTile(painter, element, grid[i][j], grid[i][j], TILE_BOUNDS(i, j), 1.0f, cornerRadii, 1.0f); + } else { + EsDrawRoundedRectangle(painter, TILE_BOUNDS(i, j), CELL_FILL, 0, ES_RECT_1(0), cornerRadii); + } + } + } + + if (!animationComplete) { + for (uintptr_t i = 0; i < animatingTileCount; i++) { + AnimatingTile *tile = &animatingTiles[i]; + EsRectangle bounds = EsRectangleLinearInterpolate(TILE_BOUNDS(tile->sourceX, tile->sourceY), TILE_BOUNDS(tile->targetX, tile->targetY), progress); + float opacity = (tile->targetOpacity - tile->sourceOpacity) * progress + tile->sourceOpacity; + DrawTile(painter, element, tile->sourceNumber, grid[tile->targetX][tile->targetY], bounds, opacity, cornerRadii, progress); + } + } + } else if (message->type == ES_MSG_ANIMATE) { + animationTimeMs += message->animate.deltaMs; + + if (animationTimeMs > ANIMATION_TIME) { + animationTimeMs = ANIMATION_TIME; + message->animate.complete = true; + } else { + message->animate.complete = false; + } + + EsElementRepaint(element); + } else if (message->type == ES_MSG_KEY_TYPED) { + if (message->keyboard.scancode == ES_SCANCODE_LEFT_ARROW) { + Update(-1, 0); + } else if (message->keyboard.scancode == ES_SCANCODE_RIGHT_ARROW) { + Update(1, 0); + } else if (message->keyboard.scancode == ES_SCANCODE_UP_ARROW) { + Update(0, -1); + } else if (message->keyboard.scancode == ES_SCANCODE_DOWN_ARROW) { + Update(0, 1); + } else { + return 0; + } + } else if (message->type == ES_MSG_GET_WIDTH || message->type == ES_MSG_GET_HEIGHT) { + float scale = EsElementGetScaleFactor(element); + message->measure.width = message->measure.height = MAIN_AREA_SIZE(); + } else { + return 0; + } + + return ES_HANDLED; +} + +int InfoPanelMessage(EsElement *element, EsMessage *message) { + if (message->type == ES_MSG_GET_WIDTH || message->type == ES_MSG_GET_HEIGHT) { + float scale = EsElementGetScaleFactor(element); + message->measure.width = MAIN_AREA_SIZE() / 2; + message->measure.height = MAIN_AREA_SIZE(); + } else { + return 0; + } + + return ES_HANDLED; +} + +void NewGameCommand(EsInstance *, EsElement *, EsCommand *) { + SaveConfiguration(); + EsMemoryZero(grid, sizeof(grid)); + score = 0; + Update(0, 0); + EsElementFocus(gameArea); +} + +void ProcessApplicationMessage(EsMessage *message) { + if (message->type == ES_MSG_INSTANCE_CREATE) { + // Create the instance. + instance = EsInstanceCreate(message, EsLiteral("2048")); + EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_OTHER); + + // Main horizontal stack. + EsPanel *panel = EsPanelCreate(instance->window, ES_CELL_FILL | ES_PANEL_HORIZONTAL, ES_STYLE_PANEL_WINDOW_BACKGROUND); + EsSpacerCreate(panel, ES_CELL_FILL); + gameArea = EsCustomElementCreate(panel, ES_ELEMENT_FOCUSABLE); + gameArea->messageUser = GameAreaMessage; + EsSpacerCreate(panel, ES_FLAGS_DEFAULT, nullptr, 30, 0); + EsPanel *info = EsPanelCreate(panel); + EsSpacerCreate(panel, ES_CELL_FILL); + + // Info panel. + info->messageUser = InfoPanelMessage; + EsTextDisplayCreate(info, ES_CELL_H_FILL, ES_STYLE_TEXT_LABEL_SECONDARY, INTERFACE_STRING(Game2048Score)); + scoreDisplay = EsTextDisplayCreate(info, ES_CELL_H_FILL, ES_STYLE_TEXT_HEADING0); + EsSpacerCreate(info, ES_FLAGS_DEFAULT, nullptr, 0, 10); + highScoreDisplay = EsTextDisplayCreate(info, ES_CELL_H_FILL | ES_TEXT_DISPLAY_RICH_TEXT, ES_STYLE_TEXT_LABEL_SECONDARY); + EsSpacerCreate(info, ES_CELL_FILL); + EsTextDisplayCreate(info, ES_CELL_H_FILL | ES_TEXT_DISPLAY_RICH_TEXT, ES_STYLE_TEXT_PARAGRAPH_SECONDARY, INTERFACE_STRING(Game2048Instructions)); + EsSpacerCreate(info, ES_FLAGS_DEFAULT, nullptr, 0, 10); + EsButton *newGame = EsButtonCreate(info, ES_CELL_H_LEFT | ES_BUTTON_NOT_FOCUSABLE, nullptr, INTERFACE_STRING(Game2048NewGame)); + newGame->accessKey = 'N'; + EsButtonOnCommand(newGame, NewGameCommand); + + // Start the game! + EsElementFocus(gameArea); + Update(0, 0); + animationTimeMs = ANIMATION_TIME; + } else if (message->type == ES_MSG_APPLICATION_EXIT) { + SaveConfiguration(); + } +} + +void _start() { + _init(); + + EsINIState state = { (char *) EsFileReadAll(EsLiteral(SETTINGS_FILE), &state.bytes) }; + + while (EsINIParse(&state)) { + if (0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("high_score"))) { + highScore = EsIntegerParse(state.value, state.valueBytes); + } + } + + while (true) { + ProcessApplicationMessage(EsMessageReceive()); + } +} diff --git a/apps/2048.ini b/apps/2048.ini new file mode 100644 index 0000000..16151bd --- /dev/null +++ b/apps/2048.ini @@ -0,0 +1,6 @@ +[general] +name=2048 +icon=icon_applications_other + +[build] +source=apps/2048.cpp diff --git a/apps/fly.cpp b/apps/fly.cpp deleted file mode 100644 index da29786..0000000 --- a/apps/fly.cpp +++ /dev/null @@ -1,942 +0,0 @@ -// TODO Icon. -// TODO Music. -// TODO Draw() with rotation. -// TODO Saving with new file IO. - -#include - -EsInstance *instance; -uint32_t backgroundColor; -int musicIndex; -bool keysPressedSpace, keysPressedEscape, keysPressedX; -uint32_t previousControllerButtons[ES_GAME_CONTROLLER_MAX_COUNT]; -uint32_t *targetBits; -size_t targetWidth, targetHeight, targetStride; -double updateTimeAccumulator; -float gameScale; -uint32_t gameOffsetX, gameOffsetY, gameWidth, gameHeight; - -#define GAME_SIZE (380) -#define BRAND "fly" - -struct Texture { - uint32_t width, height; - uint32_t *bits; -}; - -void Transform(float *destination, float *left, float *right) { - float d[6]; - d[0] = left[0] * right[0] + left[1] * right[3]; - d[1] = left[0] * right[1] + left[1] * right[4]; - d[2] = left[0] * right[2] + left[1] * right[5] + left[2]; - d[3] = left[3] * right[0] + left[4] * right[3]; - d[4] = left[3] * right[1] + left[4] * right[4]; - d[5] = left[3] * right[2] + left[4] * right[5] + left[5]; - destination[0] = d[0]; - destination[1] = d[1]; - destination[2] = d[2]; - destination[3] = d[3]; - destination[4] = d[4]; - destination[5] = d[5]; -} - -ES_FUNCTION_OPTIMISE_O3 -void Draw(Texture *texture, - float x, float y, float w = -1, float h = -1, - float sx = 0, float sy = 0, float sw = -1, float sh = -1, - float _a = 1, float _r = 1, float _g = 1, float _b = 1, - float rot = 0) { - (void) rot; - - if (sw == -1 && sh == -1) sw = texture->width, sh = texture->height; - if (w == -1 && h == -1) w = sw, h = sh; - if (_a <= 0) return; - - if (x + w < 0 || y + h < 0 || x > GAME_SIZE || y > GAME_SIZE) return; - - x *= gameScale, y *= gameScale, w *= gameScale, h *= gameScale; - - float m[6] = {}; - float m1[6] = { sw / w, 0, 0, 0, sh / h, 0 }; - float m2[6] = { 1, 0, -x * (sw / w), 0, 1, -y * (sh / h) }; - - Transform(m, m2, m1); - - intptr_t yStart = y - 1, yEnd = y + h + 1, xStart = x - 1, xEnd = x + w + 1; - // if (rot) yStart -= h * 0.45f, yEnd += h * 0.45f, xStart -= w * 0.45f, xEnd += w * 0.45f; - if (yStart < 0) yStart = 0; - if (yStart > gameHeight) yStart = gameHeight; - if (yEnd < 0) yEnd = 0; - if (yEnd > gameHeight) yEnd = gameHeight; - if (xStart < 0) xStart = 0; - if (xStart > gameWidth) xStart = gameWidth; - if (xEnd < 0) xEnd = 0; - if (xEnd > gameWidth) xEnd = gameWidth; - m[2] += m[0] * xStart, m[5] += m[3] * xStart; - - uint32_t *scanlineStart = targetBits + (gameOffsetY + yStart) * targetStride / 4 + (gameOffsetX + xStart); - - uint32_t r = _r * 255, g = _g * 255, b = _b * 255, a = _a * 255; - - for (intptr_t y = yStart; y < yEnd; y++, scanlineStart += targetStride / 4) { - uint32_t *output = scanlineStart; - - float tx = m[1] * y + m[2]; - float ty = m[4] * y + m[5]; - - for (intptr_t x = xStart; x < xEnd; x++, output++, tx += m[0], ty += m[3]) { - if (tx + sx < 0 || ty + sy < 0) continue; - uintptr_t txi = tx + sx, tyi = ty + sy; - if (txi < sx || tyi < sy || txi >= sx + sw || tyi >= sy + sh) continue; - uint32_t modified = texture->bits[tyi * texture->width + txi]; - if (!(modified & 0xFF000000)) continue; - uint32_t original = *output; - uint32_t alpha1 = (((modified & 0xFF000000) >> 24) * a) >> 8; - uint32_t alpha2 = (255 - alpha1) << 8; - uint32_t r2 = alpha2 * ((original & 0x00FF0000) >> 16); - uint32_t g2 = alpha2 * ((original & 0x0000FF00) >> 8); - uint32_t b2 = alpha2 * ((original & 0x000000FF) >> 0); - uint32_t r1 = r * alpha1 * ((modified & 0x00FF0000) >> 16); - uint32_t g1 = g * alpha1 * ((modified & 0x0000FF00) >> 8); - uint32_t b1 = b * alpha1 * ((modified & 0x000000FF) >> 0); - *output = 0xFF000000 - | (0x00FF0000 & ((r1 + r2) << 0)) - | (0x0000FF00 & ((g1 + g2) >> 8)) - | (0x000000FF & ((b1 + b2) >> 16)); - } - } -} - -void CreateTexture(Texture *texture, const char *cName) { - size_t dataBytes; - const void *data = EsEmbeddedFileGet(cName, -1, &dataBytes); - texture->bits = (uint32_t *) EsImageLoad(data, dataBytes, &texture->width, &texture->height, 4); - EsAssert(texture->bits); -} - -void ExitGame() { - EsInstanceDestroy(instance); -} - -/////////////////////////////////////////////////////////// - -#define TAG_ALL (-1) -#define TAG_SOLID (-2) -#define TAG_KILL (-3) -#define TAG_WORLD (-4) - -#define TILE_SIZE (16) - -struct Entity { - uint8_t tag; - uint8_t layer; - bool solid, kill, hide; - char symbol; - int8_t frameCount, stepsPerFrame; - Texture *texture; - float texOffX, texOffY, w, h; - int uid; - - void (*create)(Entity *); - void (*destroy)(Entity *); - void (*stepAlways)(Entity *); // Called even if level editing. - void (*step)(Entity *); - void (*draw)(Entity *); - void (*drawAfter)(Entity *); - - float x, y, px, py; - int stepIndex; - bool isUsed, isDestroyed; - - union { - struct { - float cx, cy; - float th, dth; - float dths; - int respawn, respawnGrow, dash; - } player; - - struct { - int random; - } block; - - struct { - float vel; - } moveBlock; - - struct { - float th, cx, cy; - } spin; - - struct { - float vx, vy, th, dth; - int life; - uint32_t col; - } star; - }; - - void Destroy() { - if (isDestroyed) return; - isDestroyed = true; - if (destroy) destroy(this); - } -}; - -Texture textureDashMessage, textureKeyMessage, textureKey, textureControlsMessage, textureWhite; - -Entity typePlayer, typeBlock, typeCheck, typeMoveH, typeStar, typeMoveV, typePowerup, typeShowMessage, typeKey, typeLock, typeSpin, typeEnd; - -// All the entities that can be loaded from the rooms. -Entity *entityTypes[] = { - &typeBlock, &typeCheck, &typeMoveH, &typeMoveV, &typePowerup, &typeKey, &typeLock, &typeSpin, &typeEnd, - nullptr, -}; - -int levelTick; -bool justLoaded = true; - -#define MAX_ENTITIES (1000) - -struct SaveState { - float checkX, checkY; - int roomX, roomY; - bool hasDash, hasKey; - int deathCount; - uint32_t check; -}; - -struct GameState : SaveState { - Entity entities[MAX_ENTITIES]; - int world; - Entity *player; -}; - -GameState state; - -Entity *AddEntity(Entity *templateEntity, float x, float y, int uid = 0) { - for (int i = 0; i < MAX_ENTITIES; i++) { - if (!state.entities[i].isUsed) { - EsMemoryCopy(state.entities + i, templateEntity, sizeof(Entity)); - state.entities[i].isUsed = true; - if (!state.entities[i].frameCount) state.entities[i].frameCount = 1; - if (!state.entities[i].stepsPerFrame) state.entities[i].stepsPerFrame = 1; - state.entities[i].x = state.entities[i].px = x; - state.entities[i].y = state.entities[i].py = y; - if (!state.entities[i].w) state.entities[i].w = state.entities[i].texture->width - 1; - if (!state.entities[i].h) state.entities[i].h = state.entities[i].texture->height / state.entities[i].frameCount - 1; - state.entities[i].uid = uid; - if (state.entities[i].create) state.entities[i].create(state.entities + i); - return state.entities + i; - } - } - - static Entity fake = {}; - return &fake; -} - -Entity *FindEntity(float x, float y, float w, float h, int tag, Entity *exclude) { - for (int i = 0; i < MAX_ENTITIES; i++) { - if (state.entities[i].isUsed && !state.entities[i].isDestroyed - && (state.entities[i].tag == tag - || tag == TAG_ALL - || (tag == TAG_SOLID && state.entities[i].solid) - || (tag == TAG_KILL && state.entities[i].kill) - ) - && state.entities + i != exclude) { - if (x <= state.entities[i].x + state.entities[i].w && state.entities[i].x <= x + w - && y <= state.entities[i].y + state.entities[i].h && state.entities[i].y <= y + h) { - return state.entities + i; - } - } - } - - return nullptr; -} - -char roomName[16]; - -void UpdateRoomName() { - roomName[0] = 'R'; - roomName[1] = (state.roomX / 10) + '0'; - roomName[2] = (state.roomX % 10) + '0'; - roomName[3] = '_'; - roomName[4] = (state.roomY / 10) + '0'; - roomName[5] = (state.roomY % 10) + '0'; - roomName[6] = '.'; - roomName[7] = 'D'; - roomName[8] = 'A'; - roomName[9] = 'T'; - roomName[10] = 0; -} - -#define ROOM_ID ((state.roomX - 7) + (state.roomY - 9) * 6) - -void LoadRoom() { - state.world = 0; - - UpdateRoomName(); - - roomName[6] = '_'; - const uint8_t *buffer = (const uint8_t *) EsEmbeddedFileGet(roomName, -1); - - for (int i = 0; i < MAX_ENTITIES; i++) { - if (!state.entities[i].isUsed || state.entities[i].isDestroyed) continue; - - if (state.entities[i].tag != typePlayer.tag) { - state.entities[i].Destroy(); - } else { - state.entities[i].px = state.entities[i].x; - state.entities[i].py = state.entities[i].y; - } - } - - int p = 0; - int iir = 0; - - while (true) { - uint8_t tag = buffer[p++]; - if (!tag) break; - float x = *(float *) (buffer + p); p += 4; - float y = *(float *) (buffer + p); p += 4; - - if (tag == (uint8_t) TAG_WORLD) { - state.world = x; - } - - for (int i = 0; entityTypes[i]; i++) { - if (entityTypes[i]->tag == tag) { - AddEntity(entityTypes[i], x, y, (state.roomX << 24) | (state.roomY << 16) | iir); - iir++; - } - } - } - - musicIndex = state.world; -} - -void CalculateCheck() { - state.check = 0; - - uint8_t *buffer = (uint8_t *) &state; - uint32_t check = 0x1D471D47; - - for (uintptr_t i = 0; i < sizeof(SaveState); i++) { - check ^= ((uint32_t) buffer[i] + 10) * (i + 100); - } - - state.check = check; -} - -float FadeInOut(float t) { - if (t < 0.3f) return t / 0.3f; - else if (t < 0.7f) return 1; - else return 1 - (t - 0.7f) / 0.3f; -} - -void InitialiseGame() { - state.roomX = 10; - state.roomY = 10; - - CreateTexture(&textureWhite, "white_png"); - CreateTexture(&textureKey, "key_png"); - CreateTexture(&textureDashMessage, "dash_msg_png"); - CreateTexture(&textureKeyMessage, "key_msg_png"); - CreateTexture(&textureControlsMessage, "controls_png"); - - int tag = 1; - - { - static Texture texture; - CreateTexture(&texture, "player_png"); - typePlayer.tag = tag++; - typePlayer.texture = &texture; - typePlayer.frameCount = 6; - typePlayer.stepsPerFrame = 5; - typePlayer.layer = 1; - - typePlayer.step = [] (Entity *entity) { - if (entity->player.respawn) { - if (entity->stepIndex > entity->player.respawn) { - entity->player.respawn = 0; - entity->hide = false; - entity->player.cx = state.checkX; - entity->player.cy = state.checkY; - entity->player.respawnGrow = entity->stepIndex + 20; - entity->player.dash = 0; - } else { - return; - } - } - - if (!entity->player.respawnGrow && !entity->player.dash) { - if (keysPressedSpace) { - entity->player.cx += (entity->x - entity->player.cx) * 2; - entity->player.cy += (entity->y - entity->player.cy) * 2; - entity->player.th += 3.15f; - entity->player.dth = -entity->player.dth; - entity->player.dths = 5; - } else if (keysPressedX && state.hasDash) { - entity->player.dash = 10; - } - } - - float rd = 40; - - if (entity->player.respawnGrow) { - if (entity->stepIndex > entity->player.respawnGrow) { - entity->player.respawnGrow = 0; - } else { - rd *= 1 - (entity->player.respawnGrow - entity->stepIndex) / 20.0f; - } - } - - entity->x = rd * EsCRTcosf(entity->player.th) + entity->player.cx; - entity->y = rd * EsCRTsinf(entity->player.th) + entity->player.cy + 5 * EsCRTsinf(4.71f + entity->stepIndex * 0.1f); - - if (entity->player.dash) { - float pt = entity->player.th - entity->player.dth; - float px = rd * EsCRTcosf(pt) + entity->player.cx; - float py = rd * EsCRTsinf(pt) + entity->player.cy + 5 * EsCRTsinf(4.71f + (entity->stepIndex - 1) * 0.1f); - float dx = entity->x - px; - float dy = entity->y - py; - entity->player.cx += dx * 3.2f; - entity->player.cy += dy * 3.2f; - entity->player.dash--; - AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0xFF; - } else { - entity->player.th += entity->player.dth; - } - - if (entity->player.respawnGrow) { - entity->px = entity->x; - entity->py = entity->y; - } - - if (entity->player.dths) { - entity->player.th += entity->player.dth; - entity->player.dths--; - entity->stepIndex = 5 * 3; - } - - if (FindEntity(entity->x + 5, entity->y + 5, entity->w - 10, entity->h - 10, TAG_KILL, 0)) { - for (int i = 0; i < 20; i++) { - AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0xFF0000; - } - - entity->hide = true; - entity->player.respawn = entity->stepIndex + 20; - state.deathCount++; - } - - if (entity->x > GAME_SIZE - 8) { - entity->x -= GAME_SIZE; - entity->player.cx -= GAME_SIZE; - state.checkX -= GAME_SIZE; - state.roomX++; - LoadRoom(); - } else if (entity->x < -8) { - entity->x += GAME_SIZE; - entity->player.cx += GAME_SIZE; - state.checkX += GAME_SIZE; - state.roomX--; - LoadRoom(); - } - - if (entity->y > GAME_SIZE - 8) { - entity->y -= GAME_SIZE; - entity->player.cy -= GAME_SIZE; - state.checkY -= GAME_SIZE; - state.roomY++; - LoadRoom(); - } else if (entity->y < -8) { - entity->y += GAME_SIZE; - entity->player.cy += GAME_SIZE; - state.checkY += GAME_SIZE; - state.roomY--; - LoadRoom(); - } - }; - - typePlayer.create = [] (Entity *entity) { - state.player = entity; - entity->player.cx = entity->x; - entity->player.cy = entity->y; - entity->player.dth = 0.06f; - }; - } - - { - static Texture texture; - CreateTexture(&texture, "block_png"); - - static Texture block2; - CreateTexture(&block2, "block2_png"); - - typeBlock.tag = tag++; - typeBlock.texture = &texture; - typeBlock.kill = true; - typeBlock.hide = true; - typeBlock.layer = 2; - - typeBlock.create = [] (Entity *entity) { - uint8_t r = EsRandomU8(); - - if (r < 20) { - entity->block.random = 1; - } else if (r < 50) { - entity->block.random = 2; - } else { - entity->block.random = 0; - } - }; - - typeBlock.stepAlways = [] (Entity *entity) { - if (FindEntity(entity->x + 1, entity->y + 1, entity->w - 2, entity->h - 2, entity->tag, entity)) { - entity->Destroy(); - } - }; - - typeBlock.drawAfter = [] (Entity *entity) { - if (!FindEntity(entity->x - 16, entity->y, 1, 1, entity->tag, entity)) { - Draw(&block2, entity->x - 16, entity->y, 16, 16, 0, entity->block.random * 16, 16, 16, 1); - } - - if (!FindEntity(entity->x + 16, entity->y, 1, 1, entity->tag, entity)) { - Draw(&block2, entity->x + 16, entity->y, 16, 16, 32, entity->block.random * 16, 16, 16, 1); - } - - if (!FindEntity(entity->x, entity->y - 16, 1, 1, entity->tag, entity)) { - Draw(&block2, entity->x, entity->y - 16, 16, 16, 16, entity->block.random * 16, 16, 16, 1); - } - - if (!FindEntity(entity->x, entity->y + 16, 1, 1, entity->tag, entity)) { - Draw(&block2, entity->x, entity->y + 16, 16, 16, 48, entity->block.random * 16, 16, 16, 1); - } - }; - } - - { - static Texture check1, check2; - CreateTexture(&check1, "check1_png"); - CreateTexture(&check2, "check2_png"); - typeCheck.tag = tag++; - typeCheck.texture = &check1; - - typeCheck.step = [] (Entity *entity) { - if (state.checkX == entity->x && state.checkY == entity->y) { - entity->texture = &check2; - } else { - entity->texture = &check1; - } - - if (FindEntity(entity->x - 4, entity->y - 4, entity->w + 8, entity->h + 8, typePlayer.tag, 0)) { - if (state.checkX != entity->x || state.checkY != entity->y) { - for (int i = 0; i < 10; i++) AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0xFFFFFF; - } - - state.checkX = entity->x; - state.checkY = entity->y; - - CalculateCheck(); - EsFileWriteAll("|Settings:/Save.dat", -1, &state, sizeof(SaveState)); - } - }; - } - - { - static Texture texture; - CreateTexture(&texture, "moveblock_png"); - typeMoveH.tag = tag++; - typeMoveH.texture = &texture; - typeMoveH.kill = true; - typeMoveH.w = 16; - typeMoveH.h = 16; - typeMoveH.texOffX = -4; - typeMoveH.texOffY = -4; - - typeMoveH.create = [] (Entity *entity) { - entity->moveBlock.vel = -4; - }; - - typeMoveH.step = [] (Entity *entity) { - entity->x += entity->moveBlock.vel; - - if (FindEntity(entity->x, entity->y, entity->w, entity->h, typeBlock.tag, 0)) { - entity->moveBlock.vel = -entity->moveBlock.vel; - } - }; - } - - { - // Removed entity. - tag++; - } - - { - static Texture texture; - CreateTexture(&texture, "star_png"); - typeStar.texture = &texture; - typeStar.tag = tag++; - typeStar.hide = true; // Draw manually. - typeStar.layer = 2; - - typeStar.create = [] (Entity *entity) { - float th = EsRandomU8() / 255.0 * 6.24; - float sp = EsRandomU8() / 255.0 * 0.5 + 0.5; - entity->star.vx = sp * EsCRTcosf(th); - entity->star.vy = sp * EsCRTsinf(th); - entity->star.life = EsRandomU8(); - entity->star.dth = (EsRandomU8() / 255.0f - 0.5f) * 0.2f; - }; - - typeStar.step = [] (Entity *entity) { - entity->x += entity->star.vx; - entity->y += entity->star.vy; - entity->star.th += entity->star.dth; - - if (entity->star.life < entity->stepIndex) { - entity->Destroy(); - } - }; - - typeStar.drawAfter = [] (Entity *entity) { - Draw(entity->texture, entity->x - 4, entity->y - 4, -1, -1, 0, 0, -1, -1, - 1.0 - (float) entity->stepIndex / entity->star.life, - ((entity->star.col >> 16) & 0xFF) / 255.0f, - ((entity->star.col >> 8) & 0xFF) / 255.0f, - ((entity->star.col >> 0) & 0xFF) / 255.0f, - entity->star.th); - }; - } - - { - static Texture texture; - CreateTexture(&texture, "moveblock_png"); - typeMoveV.tag = tag++; - typeMoveV.texture = &texture; - typeMoveV.kill = true; - typeMoveV.w = 16; - typeMoveV.h = 16; - typeMoveV.texOffX = -4; - typeMoveV.texOffY = -4; - - typeMoveV.create = [] (Entity *entity) { - entity->moveBlock.vel = -4; - }; - - typeMoveV.step = [] (Entity *entity) { - entity->y += entity->moveBlock.vel; - - if (FindEntity(entity->x, entity->y, entity->w, entity->h, typeBlock.tag, 0)) { - entity->moveBlock.vel = -entity->moveBlock.vel; - } - }; - } - - { - static Texture texture; - CreateTexture(&texture, "powerup_png"); - typePowerup.tag = tag++; - typePowerup.texture = &texture; - - typePowerup.step = [] (Entity *entity) { - if (state.hasDash) { - entity->Destroy(); - return; - } - - if (FindEntity(entity->x, entity->y, entity->w, entity->h, typePlayer.tag, 0)) { - state.hasDash = true; - AddEntity(&typeShowMessage, 0, 0)->texture = &textureDashMessage; - entity->Destroy(); - } - }; - } - - { - typeShowMessage.texture = &textureKeyMessage; - typeShowMessage.tag = tag++; - typeShowMessage.hide = true; - - typeShowMessage.draw = [] (Entity *entity) { - Draw(entity->texture, entity->x, entity->y, -1, -1, 0, 0, -1, -1, FadeInOut(entity->stepIndex / 180.0)); - if (entity->stepIndex > 180) entity->Destroy(); - }; - } - - { - typeKey.tag = tag++; - typeKey.texture = &textureKey; - - typeKey.step = [] (Entity *entity) { - if (state.hasKey) { - entity->Destroy(); - } else if (FindEntity(entity->x, entity->y, entity->w, entity->h, typePlayer.tag, 0)) { - state.hasKey = true; - AddEntity(&typeShowMessage, 0, 0)->texture = &textureKeyMessage; - entity->Destroy(); - for (int i = 0; i < 10; i++) AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0xFFFFFF; - } - }; - } - - { - static Texture texture; - CreateTexture(&texture, "lock_png"); - typeLock.tag = tag++; - typeLock.texture = &texture; - typeLock.kill = true; - - typeLock.step = [] (Entity *entity) { - if (state.hasKey) { - for (int i = 0; i < 1; i++) AddEntity(&typeStar, entity->x + 8, entity->y + 8)->star.col = 0x000000; - entity->Destroy(); - } - }; - } - - { - static Texture texture; - CreateTexture(&texture, "moveblock_png"); - typeSpin.tag = tag++; - typeSpin.texture = &texture; - typeSpin.kill = true; - typeSpin.w = 16; - typeSpin.h = 16; - typeSpin.texOffX = -4; - typeSpin.texOffY = -4; - - typeSpin.create = [] (Entity *entity) { - entity->spin.cx = entity->x; - entity->spin.cy = entity->y; - }; - - typeSpin.step = [] (Entity *entity) { - entity->x = 60 * EsCRTcosf(entity->spin.th) + entity->spin.cx; - entity->y = 60 * EsCRTsinf(entity->spin.th) + entity->spin.cy; - entity->spin.th += 0.04f; - }; - } - - { - static Texture msg1, msg2, msg3, num; - CreateTexture(&msg1, "end1_png"); - CreateTexture(&msg2, "end2_png"); - CreateTexture(&msg3, "end3_png"); - CreateTexture(&num, "numbers_png"); - - typeEnd.tag = tag++; - typeEnd.texture = &textureKey; - typeEnd.hide = true; - - typeEnd.create = [] (Entity *) { - state.player->Destroy(); - }; - - typeEnd.draw = [] (Entity *entity) { - float t = entity->stepIndex / 180.0f; - - if (t < 1) { - Draw(&msg1, 40, 150, -1, -1, 0, 0, -1, -1, FadeInOut(t)); - } else if (t < 2) { - Draw(&msg2, 40, 150, -1, -1, 0, 0, -1, -1, FadeInOut(t - 1)); - } else if (t < 3) { - Draw(&msg3, 40, 150, -1, -1, 0, 0, -1, -1, FadeInOut(t - 2)); - - int p = state.deathCount; - char digits[10]; - int dc = 0; - - if (p == 0) { - digits[dc++] = 0; - } else { - while (p) { - digits[dc++] = p % 10; - p /= 10; - } - } - - int w = dc * 16; - - for (int i = dc - 1; i >= 0; i--) { - Draw(&num, 40 + 150 - w / 2 + (dc - 1 - i) * 16, - 150 + 33, 16, 30, 16 * digits[i], 0, 16, 30, FadeInOut(t - 2)); - } - } else { - ExitGame(); - } - }; - } - - state.checkX = GAME_SIZE / 2; - state.checkY = GAME_SIZE / 2 - 20; - - size_t loadedStateBytes; - SaveState *loadedState = (SaveState *) EsFileReadAll("|Settings:/Save.dat", -1, &loadedStateBytes); - bool noSave = true; - - if (loadedStateBytes == sizeof(SaveState)) { - EsMemoryCopy(&state, loadedState, loadedStateBytes); - - uint32_t oldCheck = state.check; - CalculateCheck(); - EsAssert(oldCheck == state.check); - - noSave = false; - } - - LoadRoom(); - - AddEntity(&typePlayer, state.checkX, state.checkY); - - if (noSave) { - AddEntity(&typeShowMessage, 0, GAME_SIZE - 65)->texture = &textureControlsMessage; - } -} - -void UpdateGame() { - if (keysPressedEscape) { - ExitGame(); - } - - for (int i = 0; i < MAX_ENTITIES; i++) { - if (state.entities[i].isUsed) { - state.entities[i].stepIndex++; - - state.entities[i].px += (state.entities[i].x - state.entities[i].px) * 0.5f; - state.entities[i].py += (state.entities[i].y - state.entities[i].py) * 0.5f; - } - } - - for (int i = 0; i < MAX_ENTITIES; i++) if (state.entities[i].isUsed && state.entities[i].stepAlways) state.entities[i].stepAlways(state.entities + i); - - for (int i = 0; i < MAX_ENTITIES; i++) if (state.entities[i].isUsed && state.entities[i].step) { - state.entities[i].step(state.entities + i); - } - - for (int i = 0; i < MAX_ENTITIES; i++) { - if (state.entities[i].isUsed && state.entities[i].isDestroyed) state.entities[i].isUsed = false; - } - - levelTick++; - - state.world %= 3; - - if (state.world == 0) { - backgroundColor = 0xbef1b1; - } else if (state.world == 1) { - backgroundColor = 0xcee5f1; - } else if (state.world == 2) { - backgroundColor = 0xf3bdf6; - } -} - -void RenderGame() { - for (int layer = -1; layer <= 3; layer++) { - for (int i = 0; i < MAX_ENTITIES; i++) { - Entity *entity = state.entities + i; - if (!entity->isUsed) continue; - if (entity->layer != layer) continue; - if (!entity->texture) continue; - if (entity->hide) continue; - - int frame = entity->stepsPerFrame >= 0 ? ((entity->stepIndex / entity->stepsPerFrame) % entity->frameCount) : (-entity->stepsPerFrame - 1); - Draw(entity->texture, (int) (entity->px + entity->texOffX + 0.5f), - (int) (entity->py + entity->texOffY + 0.5f), - entity->texture->width, entity->texture->height / entity->frameCount, - 0, entity->texture->height / entity->frameCount * frame, - entity->texture->width, entity->texture->height / entity->frameCount); - } - } - - for (int i = 0; i < MAX_ENTITIES; i++) if (state.entities[i].isUsed && state.entities[i].draw ) state.entities[i].draw (state.entities + i); - for (int i = 0; i < MAX_ENTITIES; i++) if (state.entities[i].isUsed && state.entities[i].drawAfter ) state.entities[i].drawAfter (state.entities + i); - - if (state.hasKey) { - Draw(&textureKey, GAME_SIZE - 20, 4); - } -} - -/////////////////////////////////////////////////////////// - -int ProcessCanvasMessage(EsElement *element, EsMessage *message) { - if (message->type == ES_MSG_ANIMATE) { - message->animate.complete = false; - updateTimeAccumulator += message->animate.deltaMs / 1000.0; - - while (updateTimeAccumulator > 1 / 60.0) { - { - EsGameControllerState state[ES_GAME_CONTROLLER_MAX_COUNT]; - size_t count = EsGameControllerStatePoll(state); - - for (uintptr_t i = 0; i < count; i++) { - if (state[i].buttons & (1 << 0) && (~previousControllerButtons[i] & (1 << 0))) { - keysPressedSpace = true; - } else if (state[i].buttons & (1 << 1) && (~previousControllerButtons[i] & (1 << 1))) { - keysPressedX = true; - } - - previousControllerButtons[i] = state[i].buttons; - } - } - - UpdateGame(); - updateTimeAccumulator -= 1 / 60.0; - keysPressedSpace = keysPressedEscape = keysPressedX = false; - } - - EsElementRepaint(element); - } else if (message->type == ES_MSG_KEY_DOWN && !message->keyboard.repeat) { - if (message->keyboard.scancode == ES_SCANCODE_SPACE || message->keyboard.scancode == ES_SCANCODE_Z) { - keysPressedSpace = true; - } else if (message->keyboard.scancode == ES_SCANCODE_ESCAPE) { - keysPressedEscape = true; - } else if (message->keyboard.scancode == ES_SCANCODE_X) { - keysPressedX = true; - } - } else if (message->type == ES_MSG_PAINT) { - EsPainter *painter = message->painter; - EsPaintTargetStartDirectAccess(painter->target, &targetBits, nullptr, nullptr, &targetStride); - targetBits = (uint32_t *) ((uint8_t *) targetBits + targetStride * painter->offsetY + 4 * painter->offsetX); - targetWidth = painter->width, targetHeight = painter->height; - - gameScale = (float) painter->width / GAME_SIZE; - if (gameScale * GAME_SIZE > painter->height) gameScale = (float) painter->height / GAME_SIZE; - if (gameScale > 1) gameScale = EsCRTfloorf(gameScale); - gameWidth = GAME_SIZE * gameScale, gameHeight = GAME_SIZE * gameScale; - gameOffsetX = painter->width / 2 - gameWidth / 2; - gameOffsetY = painter->height / 2 - gameHeight / 2; - - // TODO Clear margins. - - Draw(&textureWhite, 0, 0, GAME_SIZE, GAME_SIZE, 0, 0, 1, 1, 1, - ((backgroundColor >> 16) & 0xFF) / 255.0f, - ((backgroundColor >> 8) & 0xFF) / 255.0f, - ((backgroundColor >> 0) & 0xFF) / 255.0f); - - RenderGame(); - - EsPaintTargetEndDirectAccess(painter->target); - } - - return 0; -} - -void _start() { - _init(); - - while (true) { - EsMessage *message = EsMessageReceive(); - - if (message->type == ES_MSG_INSTANCE_CREATE) { - instance = EsInstanceCreate(message, BRAND); - EsWindow *window = instance->window; - EsPanel *container = EsPanelCreate(window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER); - EsElement *canvas = EsCustomElementCreate(container, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE, {}); - canvas->messageUser = ProcessCanvasMessage; - EsElementStartAnimating(canvas); - EsElementFocus(canvas); - InitialiseGame(); - } - } -} diff --git a/apps/fly.ini b/apps/fly.ini deleted file mode 100644 index 65ad1f3..0000000 --- a/apps/fly.ini +++ /dev/null @@ -1,66 +0,0 @@ -[general] -name=Fly - -[build] -source=apps/fly.cpp - -[embed] -bgm1_mid=res/Fly Assets/bgm1.mid -bgm2_mid=res/Fly Assets/bgm2.mid -bgm3_mid=res/Fly Assets/bgm3.mid -block2_png=res/Fly Assets/block2.png -block_png=res/Fly Assets/block.png -check1_png=res/Fly Assets/check1.png -check2_png=res/Fly Assets/check2.png -controls_png=res/Fly Assets/controls.png -dash_msg_png=res/Fly Assets/dash_msg.png -end1_png=res/Fly Assets/end1.png -end2_png=res/Fly Assets/end2.png -end3_png=res/Fly Assets/end3.png -key_msg_png=res/Fly Assets/key_msg.png -key_png=res/Fly Assets/key.png -lock_png=res/Fly Assets/lock.png -moveblock_png=res/Fly Assets/moveblock.png -numbers_png=res/Fly Assets/numbers.png -player_png=res/Fly Assets/player.png -powerup_png=res/Fly Assets/powerup.png -R07_12_DAT=res/Fly Assets/R07_12.DAT -R07_13_DAT=res/Fly Assets/R07_13.DAT -R07_14_DAT=res/Fly Assets/R07_14.DAT -R07_16_DAT=res/Fly Assets/R07_16.DAT -R07_17_DAT=res/Fly Assets/R07_17.DAT -R07_18_DAT=res/Fly Assets/R07_18.DAT -R08_12_DAT=res/Fly Assets/R08_12.DAT -R08_13_DAT=res/Fly Assets/R08_13.DAT -R08_14_DAT=res/Fly Assets/R08_14.DAT -R08_16_DAT=res/Fly Assets/R08_16.DAT -R08_17_DAT=res/Fly Assets/R08_17.DAT -R08_18_DAT=res/Fly Assets/R08_18.DAT -R09_10_DAT=res/Fly Assets/R09_10.DAT -R09_11_DAT=res/Fly Assets/R09_11.DAT -R09_12_DAT=res/Fly Assets/R09_12.DAT -R09_13_DAT=res/Fly Assets/R09_13.DAT -R09_14_DAT=res/Fly Assets/R09_14.DAT -R09_15_DAT=res/Fly Assets/R09_15.DAT -R09_16_DAT=res/Fly Assets/R09_16.DAT -R09_17_DAT=res/Fly Assets/R09_17.DAT -R09_18_DAT=res/Fly Assets/R09_18.DAT -R10_09_DAT=res/Fly Assets/R10_09.DAT -R10_10_DAT=res/Fly Assets/R10_10.DAT -R10_11_DAT=res/Fly Assets/R10_11.DAT -R10_12_DAT=res/Fly Assets/R10_12.DAT -R10_13_DAT=res/Fly Assets/R10_13.DAT -R10_14_DAT=res/Fly Assets/R10_14.DAT -R10_15_DAT=res/Fly Assets/R10_15.DAT -R10_16_DAT=res/Fly Assets/R10_16.DAT -R11_09_DAT=res/Fly Assets/R11_09.DAT -R11_10_DAT=res/Fly Assets/R11_10.DAT -R11_11_DAT=res/Fly Assets/R11_11.DAT -R11_13_DAT=res/Fly Assets/R11_13.DAT -R11_14_DAT=res/Fly Assets/R11_14.DAT -R11_15_DAT=res/Fly Assets/R11_15.DAT -R12_09_DAT=res/Fly Assets/R12_09.DAT -R12_10_DAT=res/Fly Assets/R12_10.DAT -R12_11_DAT=res/Fly Assets/R12_11.DAT -star_png=res/Fly Assets/star.png -white_png=res/Fly Assets/white.png diff --git a/desktop/os.header b/desktop/os.header index 3b8ea8f..9df07b9 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -419,8 +419,6 @@ define ES_PERMISSION_POSIX_SUBSYSTEM (1 << 8) define ES_PERMISSION_ALL ((_EsLongConstant) (-1)) define ES_PERMISSION_INHERIT ((_EsLongConstant) (1) << 63) -define ES_PANEL_BAND_SIZE_DEFAULT (-1) - // Element flags - bits 0-31 for custom use; bits 32-63 common to all elements. define ES_ELEMENT_FOCUSABLE ((_EsLongConstant) (1) << 32) @@ -455,6 +453,8 @@ define ES_CELL_V_SHRINK ((_EsLongConstant) (1) << 61) define ES_CELL_V_TOP ((_EsLongConstant) (1) << 62) define ES_CELL_V_BOTTOM ((_EsLongConstant) (1) << 63) +define ES_PANEL_BAND_SIZE_DEFAULT (-1) + define ES_PANEL_STACK (0) // Default. define ES_PANEL_SWITCHER (1 << 0) define ES_PANEL_Z_STACK (1 << 1) @@ -471,6 +471,7 @@ define ES_PANEL_HORIZONTAL (1 << 8) define ES_PANEL_REVERSE (1 << 9) // Reverse layout is not supported with ES_PANEL_TABLE yet. // For ES_PANEL_TABLE. +// TODO Implement these! define ES_PANEL_H_LEFT (1 << 16) define ES_PANEL_H_RIGHT (1 << 17) define ES_PANEL_H_CENTER (1 << 18) @@ -542,6 +543,7 @@ define ES_FONT_SERIF (0xFFFE) define ES_FONT_MONOSPACED (0xFFFD) define ES_FONT_REGULAR (4) +define ES_FONT_SEMIBOLD (6) define ES_FONT_BOLD (7) define ES_TEXT_FIGURE_DEFAULT (0) @@ -2047,6 +2049,7 @@ function uint32_t EsColorBlend(uint32_t under, uint32_t over, bool fullAlpha); function uint32_t EsColorConvertToRGB(float h, float s, float v); // 0 <= hue < 6; 0 <= saturation <= 1; 0 <= value <= 1. function bool EsColorConvertToHSV(uint32_t color, float *h, float *s, float *v); function uint32_t EsColorParse(STRING string); +function uint32_t EsColorInterpolate(uint32_t from, uint32_t to, float progress); function void EsDrawBitmap(EsPainter *painter, EsRectangle region, uint32_t *bits, uintptr_t stride, uint16_t mode); // OR mode with alpha. function void EsDrawBitmapScaled(EsPainter *painter, EsRectangle destinationRegion, EsRectangle sourceRegion, uint32_t *bits, uintptr_t stride, uint16_t alpha); // Set alpha to 0xFFFF if source is opaque. @@ -2060,6 +2063,7 @@ function void EsDrawRoundedRectangle(EsPainter *painter, EsRectangle bounds, EsD function bool EsDrawStandardIcon(EsPainter *painter, uint32_t id, int size, EsRectangle region, EsDeviceColor color); function void EsDrawPaintTarget(EsPainter *painter, EsPaintTarget *source, EsRectangle destinationRegion, EsRectangle sourceRegion, uint8_t alpha); function void EsDrawText(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsRectangle *clip = ES_NULL, EsTextSelection *selectionProperties = ES_NULL); +function void EsDrawTextSimple(EsPainter *painter, EsElement *element, EsRectangle bounds, const char *string, ptrdiff_t stringBytes, EsTextStyle style, uint32_t flags = ES_FLAGS_DEFAULT); function void EsDrawTextLayers(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsTextSelection *selectionProperties = ES_NULL); function void EsDrawVectorFile(EsPainter *painter, EsRectangle bounds, const void *data, size_t dataBytes); diff --git a/desktop/prefix.h b/desktop/prefix.h index f728d6c..3b0df81 100644 --- a/desktop/prefix.h +++ b/desktop/prefix.h @@ -84,6 +84,7 @@ ES_EXTERN_C __attribute__((noreturn)) void _EsCRTlongjmp(EsCRTjmp_buf *env, int #define ES_RECT_1(x) ((EsRectangle) { (int32_t) (x), (int32_t) (x), (int32_t) (x), (int32_t) (x) }) #define ES_RECT_1I(x) ((EsRectangle) { (int32_t) (x), (int32_t) -(x), (int32_t) (x), (int32_t) -(x) }) +#define ES_RECT_1S(x) ((EsRectangle) { 0, (int32_t) (x), 0, (int32_t) (x) }) #define ES_RECT_2(x, y) ((EsRectangle) { (int32_t) (x), (int32_t) (x), (int32_t) (y), (int32_t) (y) }) #define ES_RECT_2I(x, y) ((EsRectangle) { (int32_t) (x), (int32_t) -(x), (int32_t) (y), (int32_t) -(y) }) #define ES_RECT_2S(x, y) ((EsRectangle) { 0, (int32_t) (x), 0, (int32_t) (y) }) diff --git a/desktop/styles.header b/desktop/styles.header index ace1382..4b4823d 100644 --- a/desktop/styles.header +++ b/desktop/styles.header @@ -104,6 +104,7 @@ define ES_STYLE_TEXT_LABEL (ES_STYLE_CAST(1391)) define ES_STYLE_TEXT_LABEL_INVERTED (ES_STYLE_CAST(1393)) define ES_STYLE_TEXT_LABEL_SECONDARY (ES_STYLE_CAST(1395)) define ES_STYLE_TEXT_PARAGRAPH (ES_STYLE_CAST(1397)) +define ES_STYLE_TEXT_PARAGRAPH_SECONDARY (ES_STYLE_CAST(1635)) define ES_STYLE_TEXT_TOOLBAR (ES_STYLE_CAST(1553)) define ES_STYLE_TEXTBOX_BORDERED_MULTILINE (ES_STYLE_CAST(1399)) define ES_STYLE_TEXTBOX_BORDERED_SINGLE (ES_STYLE_CAST(1401)) diff --git a/desktop/text.cpp b/desktop/text.cpp index 9b2ee65..ce3ad60 100644 --- a/desktop/text.cpp +++ b/desktop/text.cpp @@ -2566,6 +2566,15 @@ void EsDrawText(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsRect painter->clip = oldClip; } +void EsDrawTextSimple(EsPainter *painter, EsElement *element, EsRectangle bounds, const char *string, ptrdiff_t stringBytes, EsTextStyle style, uint32_t flags) { + EsTextPlanProperties properties = {}; + properties.flags = ES_TEXT_PLAN_SINGLE_USE | flags; + EsTextRun textRuns[2] = {}; + textRuns[0].style = style; + textRuns[1].offset = stringBytes == -1 ? EsCStringLength(string) : stringBytes; + EsDrawText(painter, EsTextPlanCreate(element, &properties, bounds, string, textRuns, 1), bounds); +} + #elif defined(TEXT_ELEMENTS) // --------------------------------- Markup parsing. diff --git a/desktop/theme.cpp b/desktop/theme.cpp index b8dce35..09908df 100644 --- a/desktop/theme.cpp +++ b/desktop/theme.cpp @@ -1465,25 +1465,8 @@ ThemeVariant ThemeAnimatingPropertyInterpolate(ThemeAnimatingProperty *property, float to = *(float *) (layerData + dataOffset); return (ThemeVariant) { .f32 = (float) LinearInterpolate(property->from.f32, to, position) }; } else if (property->type == THEME_OVERRIDE_COLOR) { - uint32_t from = property->from.u32; uint32_t to = *(uint32_t *) (layerData + dataOffset); - - float fa = ((from >> 24) & 0xFF) / 255.0f; - float fb = ((from >> 16) & 0xFF) / 255.0f; - float fg = ((from >> 8) & 0xFF) / 255.0f; - float fr = ((from >> 0) & 0xFF) / 255.0f; - float ta = ((to >> 24) & 0xFF) / 255.0f; - float tb = ((to >> 16) & 0xFF) / 255.0f; - float tg = ((to >> 8) & 0xFF) / 255.0f; - float tr = ((to >> 0) & 0xFF) / 255.0f; - - if (fa && !ta) { tr = fr, tg = fg, tb = fb; } - if (ta && !fa) { fr = tr, fg = tg, fb = tb; } - - return (ThemeVariant) { .u32 = (uint32_t) (LinearInterpolate(fr, tr, position) * 255.0f) << 0 - | (uint32_t) (LinearInterpolate(fg, tg, position) * 255.0f) << 8 - | (uint32_t) (LinearInterpolate(fb, tb, position) * 255.0f) << 16 - | (uint32_t) ((fa + (ta - fa) * position) * 255.0f) << 24 }; + return (ThemeVariant) { .u32 = EsColorInterpolate(property->from.u32, to, position) }; } else { EsAssert(false); return {}; @@ -2188,7 +2171,7 @@ bool UIStyle::IsRegionCompletelyOpaque(EsRectangle region, int width, int height void EsDrawRoundedRectangle(EsPainter *painter, EsRectangle bounds, EsDeviceColor mainColor, EsDeviceColor borderColor, EsRectangle borderSize, const uint32_t *cornerRadii) { ThemeLayer layer = {}; - uint8_t info[sizeof(ThemeLayerBox) + sizeof(ThemePaintSolid) * 2]; + uint8_t info[sizeof(ThemeLayerBox) + sizeof(ThemePaintSolid) * 2] = {}; ThemeLayerBox *infoBox = (ThemeLayerBox *) info; infoBox->borders = { (int8_t) borderSize.l, (int8_t) borderSize.r, (int8_t) borderSize.t, (int8_t) borderSize.b }; diff --git a/res/Fly Assets/R07_12.DAT b/res/Fly Assets/R07_12.DAT deleted file mode 100644 index f432ca9..0000000 Binary files a/res/Fly Assets/R07_12.DAT and /dev/null differ diff --git a/res/Fly Assets/R07_13.DAT b/res/Fly Assets/R07_13.DAT deleted file mode 100644 index 4a92c5d..0000000 Binary files a/res/Fly Assets/R07_13.DAT and /dev/null differ diff --git a/res/Fly Assets/R07_14.DAT b/res/Fly Assets/R07_14.DAT deleted file mode 100644 index a239e85..0000000 Binary files a/res/Fly Assets/R07_14.DAT and /dev/null differ diff --git a/res/Fly Assets/R07_16.DAT b/res/Fly Assets/R07_16.DAT deleted file mode 100644 index 4ed0aa9..0000000 Binary files a/res/Fly Assets/R07_16.DAT and /dev/null differ diff --git a/res/Fly Assets/R07_17.DAT b/res/Fly Assets/R07_17.DAT deleted file mode 100644 index 513b28d..0000000 Binary files a/res/Fly Assets/R07_17.DAT and /dev/null differ diff --git a/res/Fly Assets/R07_18.DAT b/res/Fly Assets/R07_18.DAT deleted file mode 100644 index 90fd167..0000000 Binary files a/res/Fly Assets/R07_18.DAT and /dev/null differ diff --git a/res/Fly Assets/R08_12.DAT b/res/Fly Assets/R08_12.DAT deleted file mode 100644 index 89b732d..0000000 Binary files a/res/Fly Assets/R08_12.DAT and /dev/null differ diff --git a/res/Fly Assets/R08_13.DAT b/res/Fly Assets/R08_13.DAT deleted file mode 100644 index ebb7c06..0000000 Binary files a/res/Fly Assets/R08_13.DAT and /dev/null differ diff --git a/res/Fly Assets/R08_14.DAT b/res/Fly Assets/R08_14.DAT deleted file mode 100644 index c3ee183..0000000 Binary files a/res/Fly Assets/R08_14.DAT and /dev/null differ diff --git a/res/Fly Assets/R08_16.DAT b/res/Fly Assets/R08_16.DAT deleted file mode 100644 index 7532e44..0000000 Binary files a/res/Fly Assets/R08_16.DAT and /dev/null differ diff --git a/res/Fly Assets/R08_17.DAT b/res/Fly Assets/R08_17.DAT deleted file mode 100644 index dea0d0c..0000000 Binary files a/res/Fly Assets/R08_17.DAT and /dev/null differ diff --git a/res/Fly Assets/R08_18.DAT b/res/Fly Assets/R08_18.DAT deleted file mode 100644 index d2fa08d..0000000 Binary files a/res/Fly Assets/R08_18.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_10.DAT b/res/Fly Assets/R09_10.DAT deleted file mode 100644 index 885a1c3..0000000 Binary files a/res/Fly Assets/R09_10.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_11.DAT b/res/Fly Assets/R09_11.DAT deleted file mode 100644 index 14167f6..0000000 Binary files a/res/Fly Assets/R09_11.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_12.DAT b/res/Fly Assets/R09_12.DAT deleted file mode 100644 index 90b51fa..0000000 Binary files a/res/Fly Assets/R09_12.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_13.DAT b/res/Fly Assets/R09_13.DAT deleted file mode 100644 index 6a73a66..0000000 Binary files a/res/Fly Assets/R09_13.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_14.DAT b/res/Fly Assets/R09_14.DAT deleted file mode 100644 index 92773b3..0000000 Binary files a/res/Fly Assets/R09_14.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_15.DAT b/res/Fly Assets/R09_15.DAT deleted file mode 100644 index b8d4e90..0000000 Binary files a/res/Fly Assets/R09_15.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_16.DAT b/res/Fly Assets/R09_16.DAT deleted file mode 100644 index 31f1e53..0000000 Binary files a/res/Fly Assets/R09_16.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_17.DAT b/res/Fly Assets/R09_17.DAT deleted file mode 100644 index 432130c..0000000 Binary files a/res/Fly Assets/R09_17.DAT and /dev/null differ diff --git a/res/Fly Assets/R09_18.DAT b/res/Fly Assets/R09_18.DAT deleted file mode 100644 index 2f180b0..0000000 Binary files a/res/Fly Assets/R09_18.DAT and /dev/null differ diff --git a/res/Fly Assets/R10_09.DAT b/res/Fly Assets/R10_09.DAT deleted file mode 100644 index 1c2a80a..0000000 Binary files a/res/Fly Assets/R10_09.DAT and /dev/null differ diff --git a/res/Fly Assets/R10_10.DAT b/res/Fly Assets/R10_10.DAT deleted file mode 100644 index 6e70647..0000000 Binary files a/res/Fly Assets/R10_10.DAT and /dev/null differ diff --git a/res/Fly Assets/R10_11.DAT b/res/Fly Assets/R10_11.DAT deleted file mode 100644 index 2a03887..0000000 Binary files a/res/Fly Assets/R10_11.DAT and /dev/null differ diff --git a/res/Fly Assets/R10_12.DAT b/res/Fly Assets/R10_12.DAT deleted file mode 100644 index f1cbc9d..0000000 Binary files a/res/Fly Assets/R10_12.DAT and /dev/null differ diff --git a/res/Fly Assets/R10_13.DAT b/res/Fly Assets/R10_13.DAT deleted file mode 100644 index 5488860..0000000 Binary files a/res/Fly Assets/R10_13.DAT and /dev/null differ diff --git a/res/Fly Assets/R10_14.DAT b/res/Fly Assets/R10_14.DAT deleted file mode 100644 index d848c5a..0000000 Binary files a/res/Fly Assets/R10_14.DAT and /dev/null differ diff --git a/res/Fly Assets/R10_15.DAT b/res/Fly Assets/R10_15.DAT deleted file mode 100644 index ef6e3ce..0000000 Binary files a/res/Fly Assets/R10_15.DAT and /dev/null differ diff --git a/res/Fly Assets/R10_16.DAT b/res/Fly Assets/R10_16.DAT deleted file mode 100644 index 4b3797b..0000000 Binary files a/res/Fly Assets/R10_16.DAT and /dev/null differ diff --git a/res/Fly Assets/R11_09.DAT b/res/Fly Assets/R11_09.DAT deleted file mode 100644 index 40cf3e7..0000000 Binary files a/res/Fly Assets/R11_09.DAT and /dev/null differ diff --git a/res/Fly Assets/R11_10.DAT b/res/Fly Assets/R11_10.DAT deleted file mode 100644 index 8040831..0000000 Binary files a/res/Fly Assets/R11_10.DAT and /dev/null differ diff --git a/res/Fly Assets/R11_11.DAT b/res/Fly Assets/R11_11.DAT deleted file mode 100644 index 3b457cd..0000000 Binary files a/res/Fly Assets/R11_11.DAT and /dev/null differ diff --git a/res/Fly Assets/R11_13.DAT b/res/Fly Assets/R11_13.DAT deleted file mode 100644 index 0dac4ed..0000000 Binary files a/res/Fly Assets/R11_13.DAT and /dev/null differ diff --git a/res/Fly Assets/R11_14.DAT b/res/Fly Assets/R11_14.DAT deleted file mode 100644 index 0175aeb..0000000 Binary files a/res/Fly Assets/R11_14.DAT and /dev/null differ diff --git a/res/Fly Assets/R11_15.DAT b/res/Fly Assets/R11_15.DAT deleted file mode 100644 index 39b17bc..0000000 Binary files a/res/Fly Assets/R11_15.DAT and /dev/null differ diff --git a/res/Fly Assets/R12_09.DAT b/res/Fly Assets/R12_09.DAT deleted file mode 100644 index 0f1962c..0000000 Binary files a/res/Fly Assets/R12_09.DAT and /dev/null differ diff --git a/res/Fly Assets/R12_10.DAT b/res/Fly Assets/R12_10.DAT deleted file mode 100644 index 1b0749d..0000000 Binary files a/res/Fly Assets/R12_10.DAT and /dev/null differ diff --git a/res/Fly Assets/R12_11.DAT b/res/Fly Assets/R12_11.DAT deleted file mode 100644 index 3a67d31..0000000 Binary files a/res/Fly Assets/R12_11.DAT and /dev/null differ diff --git a/res/Fly Assets/bgm1.mid b/res/Fly Assets/bgm1.mid deleted file mode 100644 index 38df148..0000000 Binary files a/res/Fly Assets/bgm1.mid and /dev/null differ diff --git a/res/Fly Assets/bgm2.mid b/res/Fly Assets/bgm2.mid deleted file mode 100644 index 0b640ed..0000000 Binary files a/res/Fly Assets/bgm2.mid and /dev/null differ diff --git a/res/Fly Assets/bgm3.mid b/res/Fly Assets/bgm3.mid deleted file mode 100644 index cff11c0..0000000 Binary files a/res/Fly Assets/bgm3.mid and /dev/null differ diff --git a/res/Fly Assets/block.png b/res/Fly Assets/block.png deleted file mode 100644 index 320e3bf..0000000 Binary files a/res/Fly Assets/block.png and /dev/null differ diff --git a/res/Fly Assets/block2.png b/res/Fly Assets/block2.png deleted file mode 100644 index ef87ee2..0000000 Binary files a/res/Fly Assets/block2.png and /dev/null differ diff --git a/res/Fly Assets/check1.png b/res/Fly Assets/check1.png deleted file mode 100644 index d1ff815..0000000 Binary files a/res/Fly Assets/check1.png and /dev/null differ diff --git a/res/Fly Assets/check2.png b/res/Fly Assets/check2.png deleted file mode 100644 index 2485fb5..0000000 Binary files a/res/Fly Assets/check2.png and /dev/null differ diff --git a/res/Fly Assets/controls.png b/res/Fly Assets/controls.png deleted file mode 100644 index 1af2e91..0000000 Binary files a/res/Fly Assets/controls.png and /dev/null differ diff --git a/res/Fly Assets/dash_msg.png b/res/Fly Assets/dash_msg.png deleted file mode 100644 index 6b2753c..0000000 Binary files a/res/Fly Assets/dash_msg.png and /dev/null differ diff --git a/res/Fly Assets/end1.png b/res/Fly Assets/end1.png deleted file mode 100644 index 80958e6..0000000 Binary files a/res/Fly Assets/end1.png and /dev/null differ diff --git a/res/Fly Assets/end2.png b/res/Fly Assets/end2.png deleted file mode 100644 index 3d31c1a..0000000 Binary files a/res/Fly Assets/end2.png and /dev/null differ diff --git a/res/Fly Assets/end3.png b/res/Fly Assets/end3.png deleted file mode 100644 index 4b98e61..0000000 Binary files a/res/Fly Assets/end3.png and /dev/null differ diff --git a/res/Fly Assets/key.png b/res/Fly Assets/key.png deleted file mode 100644 index ee6efb5..0000000 Binary files a/res/Fly Assets/key.png and /dev/null differ diff --git a/res/Fly Assets/key_msg.png b/res/Fly Assets/key_msg.png deleted file mode 100644 index 81cbe3e..0000000 Binary files a/res/Fly Assets/key_msg.png and /dev/null differ diff --git a/res/Fly Assets/lock.png b/res/Fly Assets/lock.png deleted file mode 100644 index 3fa83df..0000000 Binary files a/res/Fly Assets/lock.png and /dev/null differ diff --git a/res/Fly Assets/moveblock.png b/res/Fly Assets/moveblock.png deleted file mode 100644 index b5bdae0..0000000 Binary files a/res/Fly Assets/moveblock.png and /dev/null differ diff --git a/res/Fly Assets/numbers.png b/res/Fly Assets/numbers.png deleted file mode 100644 index c273e71..0000000 Binary files a/res/Fly Assets/numbers.png and /dev/null differ diff --git a/res/Fly Assets/player.png b/res/Fly Assets/player.png deleted file mode 100644 index 44526ab..0000000 Binary files a/res/Fly Assets/player.png and /dev/null differ diff --git a/res/Fly Assets/powerup.png b/res/Fly Assets/powerup.png deleted file mode 100644 index 93400ea..0000000 Binary files a/res/Fly Assets/powerup.png and /dev/null differ diff --git a/res/Fly Assets/star.png b/res/Fly Assets/star.png deleted file mode 100644 index dfe9b56..0000000 Binary files a/res/Fly Assets/star.png and /dev/null differ diff --git a/res/Fly Assets/white.png b/res/Fly Assets/white.png deleted file mode 100644 index 5e65d7a..0000000 Binary files a/res/Fly Assets/white.png and /dev/null differ diff --git a/res/Theme Source.dat b/res/Theme Source.dat index d86a5d9..b11971f 100644 Binary files a/res/Theme Source.dat and b/res/Theme Source.dat differ diff --git a/res/Themes/Theme.dat b/res/Themes/Theme.dat index 6db90e4..40d687d 100644 Binary files a/res/Themes/Theme.dat and b/res/Themes/Theme.dat differ diff --git a/shared/math.cpp b/shared/math.cpp index f8e88bf..911eea9 100644 --- a/shared/math.cpp +++ b/shared/math.cpp @@ -100,6 +100,25 @@ EsRectangle EsRectangleLinearInterpolate(EsRectangle from, EsRectangle to, float LinearInterpolate(from.t, to.t, progress), LinearInterpolate(from.b, to.b, progress)); } +uint32_t EsColorInterpolate(uint32_t from, uint32_t to, float progress) { + float fa = ((from >> 24) & 0xFF) / 255.0f; + float fb = ((from >> 16) & 0xFF) / 255.0f; + float fg = ((from >> 8) & 0xFF) / 255.0f; + float fr = ((from >> 0) & 0xFF) / 255.0f; + float ta = ((to >> 24) & 0xFF) / 255.0f; + float tb = ((to >> 16) & 0xFF) / 255.0f; + float tg = ((to >> 8) & 0xFF) / 255.0f; + float tr = ((to >> 0) & 0xFF) / 255.0f; + + if (fa && !ta) { tr = fr, tg = fg, tb = fb; } + if (ta && !fa) { fr = tr, fg = tg, fb = tb; } + + return (uint32_t) (LinearInterpolate(fr, tr, progress) * 255.0f) << 0 + | (uint32_t) (LinearInterpolate(fg, tg, progress) * 255.0f) << 8 + | (uint32_t) (LinearInterpolate(fb, tb, progress) * 255.0f) << 16 + | (uint32_t) (LinearInterpolate(fa, ta, progress) * 255.0f) << 24; +} + float RubberBand(float original, float target) { float sign = SignFloat(original - target); float distance = AbsoluteFloat(original - target); diff --git a/shared/strings.cpp b/shared/strings.cpp index 4c9bb2a..c3a1d45 100644 --- a/shared/strings.cpp +++ b/shared/strings.cpp @@ -264,6 +264,16 @@ DEFINE_INTERFACE_STRING(FileManagerListContextActions, "Actions"); DEFINE_INTERFACE_STRING(FileManagerCopyTask, "Copying" ELLIPSIS); DEFINE_INTERFACE_STRING(FileManagerMoveTask, "Moving" ELLIPSIS); +// 2048. + +DEFINE_INTERFACE_STRING(Game2048Score, "Score:"); +DEFINE_INTERFACE_STRING(Game2048Instructions, "Use the \aw6]arrow-keys\a] to slide the tiles. When matching tiles touch, they \aw6]merge\a] into one. Try to create the number \aw6]2048\a]!"); +DEFINE_INTERFACE_STRING(Game2048GameOver, "Game over"); +DEFINE_INTERFACE_STRING(Game2048GameOverExplanation, "There are no valid moves left."); +DEFINE_INTERFACE_STRING(Game2048NewGame, "New game"); +DEFINE_INTERFACE_STRING(Game2048HighScore, "High score: \aw6]%d\a]"); +DEFINE_INTERFACE_STRING(Game2048NewHighScore, "You reached a new high score!"); + // TODO System Monitor. #pragma GCC diagnostic pop diff --git a/util/api_table.ini b/util/api_table.ini index 5d03d9d..d867a8a 100644 --- a/util/api_table.ini +++ b/util/api_table.ini @@ -440,3 +440,5 @@ EsTextboxSetFont=438 EsTextboxSetTextSize=439 EsRectangleLinearInterpolate=440 EsDrawRoundedRectangle=441 +EsDrawTextSimple=442 +EsColorInterpolate=443