Cleanup and hopefully improve the package level select menu

Unfortunately it doesn't entirely adapt to window resizing, but it's slightly better now... ;)
This commit is contained in:
ROllerozxa 2026-06-21 21:56:36 +02:00
commit e7ddb1a19b
3 changed files with 150 additions and 201 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 KiB

View file

@ -9,8 +9,6 @@
#include "widget_manager.hh"
#include "settings.hh"
#include <unistd.h>
// Disables level completion check in packages
#define UNLOCK_ALL_LVLS false
@ -25,9 +23,7 @@
#define _ICON_HEIGHT _ICON_WIDTH//(1.5f*_tms.yppcm)
#define _BLOCK_SPACING (_tms.xppcm)
static void
menu_pkg_render(struct tms_wdg *w, struct tms_surface *s)
{
static void menu_pkg_render(struct tms_wdg *w, struct tms_surface *s) {
principia_wdg *pwdg = static_cast<principia_wdg*>(w->data2);
float px, py;
@ -39,34 +35,19 @@ menu_pkg_render(struct tms_wdg *w, struct tms_surface *s)
py = w->pos.y;
}
float r = 0.f;
tms_ddraw_sprite_r(s->ddraw, w->s[0], px, py, w->size.x, w->size.y, 0.f);
if (_tms.emulating_portrait) {
int xx = (int)px, yy = (int)py;
tms_convert_to_portrait(&xx, &yy);
px = (float)xx;
py = (float)yy;
r = -90.f;
}
tms_ddraw_sprite_r(s->ddraw, w->s[0], px, py, w->size.x, w->size.y, r);
if (w->s[1]) {
tms_ddraw_sprite_r(s->ddraw, w->s[1], px, py, w->size.x/2.f, w->size.y/2.f,r);
}
if (w->s[1])
tms_ddraw_sprite_r(s->ddraw, w->s[1], px, py, w->size.x/2.f, w->size.y/2.f, 0.f);
}
static bool down[MAX_P];
static tvec2 touch_pos[MAX_P];
static uint64_t touch_time[MAX_P];
static bool dragging[MAX_P];
static struct tms_texture *_tex_bg = 0;
static struct tms_texture *tex_overlay = 0;
static struct tms_atlas *tex_icons = 0;
static pkginfo main_pkg;
struct lvlcache {
uint32_t id;
struct tms_sprite *sprite;
@ -78,30 +59,19 @@ struct lvlcache {
static int unlock_count = 0;
static struct lvlcache *cache = 0;
bool
menu_pkg::widget_clicked(principia_wdg *w, uint8_t button_id, int pid)
{
if (menu_base::widget_clicked(w, button_id, pid)) {
bool menu_pkg::widget_clicked(principia_wdg *w, uint8_t button_id, int pid) {
if (menu_base::widget_clicked(w, button_id, pid))
return true;
if (button_id == BTN_BACK) {
P.add_action(ACTION_GOTO_PLAY, 0x1);
return true;
}
switch (button_id) {
case BTN_BACK:
P.add_action(ACTION_GOTO_MAINMENU, 0x1);
//P.add_action(ACTION_GOTO_PLAY, 0x1);
break;
default: return false;
}
return true;
return false;
}
menu_pkg::menu_pkg()
: menu_base(false)
{
this->scale = 1.f;
void menu_pkg::recalculate_layout() {
base_x = _BASE_X * scale;
base_y = _BASE_Y * scale;
icon_width = _ICON_WIDTH * scale;
@ -110,18 +80,7 @@ menu_pkg::menu_pkg()
icon_height = _ICON_HEIGHT * scale;
block_spacing = _BLOCK_SPACING * scale;
main_pkg.num_levels = 2;
main_pkg.levels = (uint32_t*)malloc(2*sizeof(uint32_t));
main_pkg.levels[0] = 118;
main_pkg.levels[1] = 119;
this->pkg = main_pkg;
this->dd = this->get_surface()->ddraw;
this->cam = tms_camera_alloc();
this->cam_screen = tms_camera_alloc();
tex_icons = tms_atlas_alloc(1024,1024,3);
this->cam->_position = (tvec3){0.f, -base_y - _tms.window_height/2.f, 0.f};
this->cam->_direction = (tvec3){0.f, 0.f, -1.f};
this->cam->owidth = this->cam->width = _tms.window_width;
@ -129,6 +88,15 @@ menu_pkg::menu_pkg()
this->cam->_velocity.x = .5f;
this->refresh_widgets();
}
menu_pkg::menu_pkg() : menu_base(false) {
this->scale = 1.f;
this->dd = this->get_surface()->ddraw;
tex_icons = tms_atlas_alloc(1024,1024,3);
this->wm->remove_all();
this->wdg_back = this->wm->create_widget(
@ -141,16 +109,21 @@ menu_pkg::menu_pkg()
this->wdg_back->priority = 500;
this->wdg_back->add();
recalculate_layout();
tex_overlay = tms_texture_alloc();
tms_texture_load(tex_overlay, "data/textures/ui/icon_overlay.png");
tex_overlay->format = GL_RGBA;
tms_texture_set_filtering(tex_overlay, GL_LINEAR);
tms_texture_upload(tex_overlay);
}
bool
menu_pkg::set_pkg(int type, uint32_t id)
{
if (type == LEVEL_MAIN && id == 7) {
bool menu_pkg::set_pkg(int type, uint32_t id) {
if (type == LEVEL_MAIN && id == 7)
settings["has_opened_classic_puzzles"]->v.b = true;
}
tms_infof("set pkg");
tms_infof("menu_pkg: set pkg");
if (!(this->pkg.open(type,id))) {
tms_errorf("could not open package!");
return false;
@ -172,7 +145,7 @@ menu_pkg::set_pkg(int type, uint32_t id)
if (cache) free(cache);
cache = (struct lvlcache*)malloc(this->pkg.num_levels*sizeof(struct lvlcache));
for (int x=0; x<this->pkg.num_levels; x++) {
for (int x = 0; x < this->pkg.num_levels; x++) {
uint32_t lvl_id = this->pkg.levels[x];
memset(info.icon, 0, sizeof(info.icon));
@ -181,64 +154,47 @@ menu_pkg::set_pkg(int type, uint32_t id)
FILE_IN_ASSET(this->pkg.type == LEVEL_MAIN);
FILE *fp = _fopen(filename, "rb");
if (fp) {
buf.reset();
_fread(buf.buf, 1, sizeof(lvlinfo), fp);
buf.size = sizeof(lvlinfo);
info.read(&buf, true);
tms_infof("read level %.*s", info.name_len, info.name);
memcpy(cache[x].icon, info.icon, 128*128);
int nn = 0;
int n_max = 0;
for (int y=0; y<128*128; y++) {
if (cache[x].icon[y] != 0) nn ++;
if (cache[x].icon[y] > n_max) n_max = cache[x].icon[y];
}
tms_infof("num not zero: %d, max:%d", nn, n_max);
cache[x].id = lvl_id;
cache[x].sprite = tms_atlas_add_bitmap(tex_icons, 128, -128, 1, info.icon);
cache[x].progress = progress::get_level_progress(type, lvl_id);
cache[x].show_score = info.show_score;
} else {
if (!fp) {
tms_errorf("file in package was missing");
return false;
}
buf.reset();
_fread(buf.buf, 1, sizeof(lvlinfo), fp);
buf.size = sizeof(lvlinfo);
info.read(&buf, true);
tms_infof("read level %.*s", info.name_len, info.name);
memcpy(cache[x].icon, info.icon, 128*128);
int nn = 0;
int n_max = 0;
for (int y=0; y<128*128; y++) {
if (cache[x].icon[y] != 0) nn ++;
if (cache[x].icon[y] > n_max) n_max = cache[x].icon[y];
}
tms_infof("num not zero: %d, max:%d", nn, n_max);
cache[x].id = lvl_id;
cache[x].sprite = tms_atlas_add_bitmap(tex_icons, 128, -128, 1, info.icon);
cache[x].progress = progress::get_level_progress(type, lvl_id);
cache[x].show_score = info.show_score;
_fclose(fp);
}
tms_texture_upload(&tex_icons->texture);
tms_infof("texture id of icons tex %u", tex_icons->texture.gl_texture);
tms_infof("successfully set pkg");
return true;
}
int
menu_pkg::resume(void)
{
tms_infof("Resume menu_pkg");
if (_tex_bg) tms_texture_free(_tex_bg);
if (tex_overlay) tms_texture_free(tex_overlay);
int menu_pkg::resume() {
tms_infof("menu_pkg: resume")
active = true;
_tex_bg = tms_texture_alloc();
recalculate_layout();
tms_texture_load(_tex_bg, "data/textures/pkgmenubg.png");
_tex_bg->format = GL_RGBA;
tms_texture_set_filtering(_tex_bg, GL_LINEAR);
tms_texture_upload(_tex_bg);
tex_overlay = tms_texture_alloc();
tms_texture_load(tex_overlay, "data/textures/ui/icon_overlay.png");
tex_overlay->format = GL_RGBA;
tms_texture_set_filtering(tex_overlay, GL_LINEAR);
tms_texture_upload(tex_overlay);
for (int x=0; x<MAX_P; x++) {
for (int x = 0; x < MAX_P; x++) {
down[x] = false;
dragging[x] = false;
}
@ -256,45 +212,30 @@ menu_pkg::resume(void)
/* calculate unlock count */
unlock_count = 0;
for (int x=0; x<this->pkg.num_levels; x++) {
if (cache[x].progress->completed) {
for (int x = 0; x < this->pkg.num_levels; x++) {
if (cache[x].progress->completed)
unlock_count ++;
}
}
unlock_count += this->pkg.unlock_count;
tms_infof("pkg resume finished");
return T_OK;
}
int
menu_pkg::pause(void)
{
tms_infof("PAUSE");
if (_tex_bg) {
tms_texture_free(_tex_bg);
_tex_bg = 0;
}
if (tex_overlay) {
tms_texture_free(tex_overlay);
tex_overlay = 0;
}
int menu_pkg::pause() {
active = false;
return T_OK;
}
int
menu_pkg::step(double dt)
{
int menu_pkg::step(double dt) {
float damping = powf(.025f, dt);
this->cam->_velocity.x *= damping;
this->cam->_position.x += this->cam->_velocity.x * dt;
//this->cam->_position.x += .002f;
this->cam->near = -1.f;
this->cam->far = 1.f;
float max_x = this->pkg.num_levels/9 * _tms.xppcm*4.f*1.2f + 2000;
float max_x = (int)((float)this->pkg.num_levels / 9) * _tms.xppcm*4.f*1.2f + 2000;
float min_x = _tms.window_width/2.f - 200.f;
this->cam->_position.x = tclampf(this->cam->_position.x, min_x, max_x);
@ -304,13 +245,24 @@ menu_pkg::step(double dt)
return T_OK;
}
int
menu_pkg::render()
{
tvec2 menu_pkg::get_cell_pos(int x) {
int block = x / 9;
float sx = base_x + (x % 3) * icon_outer + (float)block * (block_spacing + 3.f * icon_outer);
float sy = base_y - (int)((float)(x % 9) / 3) * icon_outer;
return (tvec2){sx, sy};
}
bool menu_pkg::is_unlocked(int x) {
return UNLOCK_ALL_LVLS || this->pkg.unlock_count == 0 || x < unlock_count || cache[x].progress->completed;
}
int menu_pkg::render() {
glDisable(GL_DEPTH_TEST);
glDepthMask(0);
tms_texture_render(_tex_bg);
glClearColor(0.05f, 0.05f, 0.05f, 1.f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_icons->texture.gl_texture);
@ -325,33 +277,31 @@ menu_pkg::render()
tms_ddraw_set_matrices(this->dd, this->cam->view, this->cam->projection);
for (int x=0; x<this->pkg.num_levels; x++) {
int block = x / 9;
float sx = base_x + (x%3)*icon_outer + (float)block * (block_spacing + 3.f*icon_outer);
float sy = base_y - (x%9)/3*icon_outer;
// Draw level icons
for (int x = 0; x < this->pkg.num_levels; x++) {
tvec2 pos = this->get_cell_pos(x);
if (UNLOCK_ALL_LVLS || this->pkg.unlock_count == 0 || x < unlock_count || cache[x].progress->completed)
tms_ddraw_sprite(this->dd, cache[x].sprite, sx, sy, icon_width*scale, icon_height*scale);
if (is_unlocked(x))
tms_ddraw_sprite(this->dd, cache[x].sprite, pos.x, pos.y, icon_width*scale, icon_height*scale);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_overlay->gl_texture);
for (int x=0; x<this->pkg.num_levels; x++) {
int block = x / 9;
float sx = base_x + (x%3)*icon_outer + (float)block * (block_spacing + 3.f*icon_outer);
float sy = base_y - (x%9)/3*icon_outer;
// Draw icon overlays
for (int x = 0; x < this->pkg.num_levels; x++) {
tvec2 pos = this->get_cell_pos(x);
struct tms_sprite overlay;
overlay.bl = (tvec2){0.f, 0.f};
overlay.tr = (tvec2){1.f, 1.f};
if (UNLOCK_ALL_LVLS || this->pkg.unlock_count == 0 || x < unlock_count || cache[x].progress->completed)
if (is_unlocked(x))
tms_ddraw_set_color(this->dd, 0.75f, 1.f, .75f, 1.f);
else
tms_ddraw_set_color(this->dd, 1.f, .75f, .75f, 1.f);
tms_ddraw_sprite(this->dd, &overlay, sx, sy, (icon_width+7.f)*scale, (icon_height+7.f)*scale);
tms_ddraw_sprite(this->dd, &overlay, pos.x, pos.y, (icon_width+7.f)*scale, (icon_height+7.f)*scale);
}
tms_ddraw_set_color(this->dd, 1.f, 1.f, 1.f, 1.f);
@ -359,35 +309,33 @@ menu_pkg::render()
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gui_spritesheet::atlas->texture.gl_texture);
for (int x=0; x<this->pkg.num_levels; x++) {
int block = x / 9;
float sx = base_x + (x%3)*icon_outer + (float)block * (block_spacing + 3.f*icon_outer);
float sy = base_y - (x%9)/3*icon_outer;
// Draw other stuff
for (int x = 0; x < this->pkg.num_levels; x++) {
tvec2 pos = this->get_cell_pos(x);
char ss[32];
if (cache[x].progress->completed) {
tms_ddraw_sprite(this->dd, gui_spritesheet::get_sprite(S_CHECKMARK),
sx + icon_outer/2.f - 48.f*scale,
sy - icon_outer/2.f + 64.f*scale,
pos.x + icon_outer/2.f - 48.f*scale,
pos.y - icon_outer/2.f + 64.f*scale,
gui_spritesheet::get_sprite(S_CHECKMARK)->width*scale, gui_spritesheet::get_sprite(S_CHECKMARK)->height*scale);
}
if (UNLOCK_ALL_LVLS || this->pkg.unlock_count == 0 || x < unlock_count || cache[x].progress->completed) {
if (cache[x].show_score) {
sprintf(ss, "%d", cache[x].progress->top_score);
if (is_unlocked(x) && cache[x].show_score) {
// Render score at bottom-left
sprintf(ss, "%d", cache[x].progress->top_score);
float x = sx - icon_width/2.f;
float y = sy - icon_height/2.f + _tms.yppcm*.125f;
float x = pos.x - icon_width/2.f;
float y = pos.y - icon_height/2.f + _tms.yppcm*.125f;
this->add_text(ss, font::xmedium, x, y, TV_WHITE);
}
this->add_text(ss, font::xmedium, x, y, TV_WHITE);
}
/* render the order number of this level */
// render the order number of this level
sprintf(ss, "%d", x+1);
float _x = sx - icon_width/2.f;
float _y = sy + icon_height/2.f - _tms.yppcm * .25f*scale;
float _x = pos.x - icon_width/2.f;
float _y = pos.y + icon_height/2.f - _tms.yppcm * .25f*scale;
this->add_text(ss, font::large, _x, _y, TV_WHITE);
}
@ -403,9 +351,7 @@ menu_pkg::render()
return T_OK;
}
int
menu_pkg::handle_input(tms::event *ev, int action)
{
int menu_pkg::handle_input(tms::event *ev, int action) {
if (pscreen::handle_input(ev, action) == EVENT_DONE) {
return EVENT_DONE;
}
@ -472,39 +418,40 @@ menu_pkg::handle_input(tms::event *ev, int action)
if (btn_x >= 0 && btn_x < 3 && btn_y >= 0 && btn_y < 3 && btn >= 0 && btn < this->pkg.num_levels) {
tms_infof("clicked %d", btn);
if (UNLOCK_ALL_LVLS || this->pkg.unlock_count == 0 || btn < unlock_count || cache[btn].progress->completed) {
uint32_t level_id = this->pkg.levels[btn];
G->play_sound(SND_CLICK, 0.0f, 0.0f, 0, .5f);
if (!is_unlocked(btn)) {
ui::message("This level is locked. Please complete more levels to access this level.");
return T_OK;
}
bool test_playing = false;
G->screen_back = this;
if (this->pkg.type == LEVEL_MAIN && this->pkg.id == 7) {
// XXX: causes segfaults on android
uint32_t level_id = this->pkg.levels[btn];
G->play_sound(SND_CLICK, 0.0f, 0.0f, 0, .5f, false, 0, true);
bool test_playing = false;
G->screen_back = this;
if (this->pkg.type == LEVEL_MAIN && this->pkg.id == 7) {
// XXX: causes segfaults on android
#ifndef TMS_BACKEND_ANDROID
char filename[1024];
snprintf(filename, 1023, "%s/7.%d.psol", pkgman::get_level_path(LEVEL_LOCAL), level_id);
char filename[1024];
snprintf(filename, 1023, "%s/7.%d.psol", pkgman::get_level_path(LEVEL_LOCAL), level_id);
if (file_exists(filename)) {
open_play_data *opd = new open_play_data(LEVEL_LOCAL, level_id, &pkg, false, 1);
ui::confirm("Do you want to load your last saved solution?",
"Yes", principia_action(ACTION_OPEN_MAIN_PUZZLE_SOLUTION, opd),
"No", principia_action(ACTION_CREATE_MAIN_PUZZLE_SOLUTION, opd),
"Cancel", principia_action(ACTION_IGNORE, 0));
} else
if (file_exists(filename)) {
open_play_data *opd = new open_play_data(LEVEL_LOCAL, level_id, &pkg, false, 1);
ui::confirm("Do you want to load your last saved solution?",
"Yes", principia_action(ACTION_OPEN_MAIN_PUZZLE_SOLUTION, opd),
"No", principia_action(ACTION_CREATE_MAIN_PUZZLE_SOLUTION, opd),
"Cancel", principia_action(ACTION_IGNORE, 0));
} else
#endif
{
P.add_action(ACTION_CREATE_MAIN_PUZZLE_SOLUTION, new open_play_data(LEVEL_LOCAL, level_id, &pkg, false, 1));
}
return T_OK;
{
P.add_action(ACTION_CREATE_MAIN_PUZZLE_SOLUTION, new open_play_data(LEVEL_LOCAL, level_id, &pkg, false, 1));
}
G->open_play(this->pkg.type, level_id, &this->pkg, test_playing, 0);
G->resume_action = GAME_RESUME_OPEN;
tms::set_screen(G);
} else {
ui::message("This level is locked. Please complete more levels to access this level.");
return T_OK;
}
G->open_play(this->pkg.type, level_id, &this->pkg, test_playing, 0);
G->resume_action = GAME_RESUME_OPEN;
tms::set_screen(G);
}
}
}
@ -512,18 +459,15 @@ menu_pkg::handle_input(tms::event *ev, int action)
return T_OK;
}
void
menu_pkg::window_size_changed()
{
if (this->get_surface() && this->get_surface()->ddraw) {
float projection[16];
tmat4_set_ortho(projection, 0, _tms.window_width, 0, _tms.window_height, 1, -1);
tms_ddraw_set_matrices(this->get_surface()->ddraw, 0, projection);
}
void menu_pkg::window_size_changed() {
// XXX: This whole menu is a mess and does not play well with window resizing. Go back to the
// play menu if the window is resized while in the package menu.
if (active)
tms::set_screen(P.s_menu_play);
this->refresh_widgets();
}
void
menu_pkg::refresh_widgets()
{
void menu_pkg::refresh_widgets() {
this->wm->rearrange();
}

View file

@ -4,11 +4,9 @@
#include "pkgman.hh"
#include <tms/cpp.hh>
class menu_pkg : public menu_base
{
class menu_pkg : public menu_base {
pkginfo pkg;
struct tms_camera *cam;
struct tms_camera *cam_screen;
struct tms_ddraw *dd;
float scale;
@ -20,17 +18,24 @@ class menu_pkg : public menu_base
float icon_height;
float block_spacing;
bool active;
public:
menu_pkg();
bool set_pkg(int type, uint32_t id);
int render();
int resume(void);
int pause(void);
int resume();
int pause();
int step(double dt);
int handle_input(tms::event *ev, int action);
void window_size_changed();
void refresh_widgets();
bool widget_clicked(principia_wdg *w, uint8_t button_id, int pid);
void recalculate_layout();
tvec2 get_cell_pos(int cell);
bool is_unlocked(int cell);
};