Purple Martians
Technical Code Descriptions
Display
Global variables
Creating the display
Process screen change
Display transform double
Detecting window move
Global variables
I use these global variables for the display:
ALLEGRO_DISPLAY *display;
int fullscreen;
// current size and position
int disp_x_curr;
int disp_y_curr;
int disp_w_curr;
int disp_h_curr;
// size and position of windowed mode
int disp_x_wind;
int disp_y_wind;
int disp_w_wind;
int disp_h_wind;
// In windowed mode current values are same as windowed values.
// In fullscreen mode, they are read from the display struct.
int display_transform_double = 2;
int SCREEN_W;
int SCREEN_H;
These values are also saved in the config file:
int fullscreen;
int disp_x_wind;
int disp_y_wind;
int disp_w_wind;
int disp_h_wind;
Creating the display
int init_screen(void)
{
al_set_new_display_option(ALLEGRO_COLOR_SIZE, 16, ALLEGRO_SUGGEST);
// (most of the time I get a 32 bit anyway, but if I get 16, it can be faster)
int flags = ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE;
if (fullscreen) flags = ALLEGRO_FULLSCREEN_WINDOW | ALLEGRO_RESIZABLE;
al_set_new_display_flags(flags);
display = al_create_display(disp_w_wind, disp_h_wind);
if(!display)
{
sprintf(msg, "Error creating display\n");
m_err(msg);
exit(0);
}
if (!fullscreen)
{
disp_x_curr = disp_x_wind;
disp_y_curr = disp_y_wind;
al_set_window_position(display, disp_x_curr, disp_y_curr);
}
disp_w_curr = al_get_display_width(display);
disp_h_curr = al_get_display_height(display);
al_get_window_position(display, &disp_x_curr, &disp_y_curr);
auto_set_display_transform_double();
return 1;
}
Process screen change
This function is called when:
- an event 'ALLEGRO_EVENT_DISPLAY_RESIZE' is received
- F12 is used to toggle fullscreen
- proc_controllers() detects the window has been moved
void proc_screen_change(int new_sw, int new_sh, int new_sx, int new_sy, int new_fs)
{
if ((!fullscreen) && (new_fs)) // changing to fullscreen
{
fullscreen = 1;
al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, 1);
al_get_window_position(display, &disp_x_curr, &disp_y_curr);
disp_w_curr = al_get_display_width(display);
disp_h_curr = al_get_display_height(display);
auto_set_display_transform_double();
rebuild_bitmaps();
save_config();
Redraw = 1;
}
else if ((fullscreen) && (!new_fs)) // changing away from fullscreen
{
fullscreen = 0;
al_resize_display(display, disp_w_wind, disp_h_wind);
al_set_display_flag(display, ALLEGRO_FULLSCREEN_WINDOW, 0);
al_set_window_position(display, disp_x_wind, disp_y_wind);
al_get_window_position(display, &disp_x_curr, &disp_y_curr);
disp_w_curr = al_get_display_width(display);
disp_h_curr = al_get_display_height(display);
auto_set_display_transform_double();
rebuild_bitmaps();
save_config();
Redraw = 1;
}
else if (!fullscreen)
{
if ((new_sw != disp_w_curr) || (new_sh != disp_h_curr)) // window has been resized
{
al_acknowledge_resize(display);
disp_w_curr = disp_w_wind = al_get_display_width(display);
disp_h_curr = disp_h_wind = al_get_display_height(display);
auto_set_display_transform_double();
rebuild_bitmaps();
save_config();
Redraw = 1;
}
if ((new_sx != disp_x_curr) || (new_sy != disp_y_curr)) // window has been moved
{
disp_x_curr = disp_x_wind = new_sx;;
disp_y_curr = disp_y_wind = new_sy;;
save_config();
}
}
}
Display transform double
I also use an orthographic transform to double or triple the screen size.
This was implemented to address large screen sizes and small text on menus and overlays.
void set_display_transform(void)
{
al_set_target_backbuffer(display);
SCREEN_W = disp_w_curr/display_transform_double;
SCREEN_H = disp_h_curr/display_transform_double;
ALLEGRO_TRANSFORM trans;
al_identity_transform(&trans);
al_orthographic_transform(&trans, 0, 0, -1.0, SCREEN_W, SCREEN_H, 1.0);
al_use_projection_transform(&trans);
}
void auto_set_display_transform_double(void)
{
display_transform_double = 1;
if (disp_w_curr > 1023) display_transform_double = 2;
if (disp_h_curr > 1023) display_transform_double = 2;
if (disp_w_curr < 1024) display_transform_double = 1;
if (disp_h_curr < 700) display_transform_double = 1;
if (level_editor_running) display_transform_double = 1;
if (help_screens_running)
{
if (disp_w_curr > 1279) display_transform_double = 2;
if (disp_w_curr < 1280) display_transform_double = 1;
}
set_display_transform();
set_map_var();
}
This extern variable controls the doubling:
extern int display_transform_double = 1;
// 1 = normal (no double)
// 2 = double
// 3 = triple
Then all of my drawing functions throughout the rest of the game that need to know screen size use
the prescaled 'SCREEN_W' and 'SCREEN_H' instead of the actual sizes.
The mouse_x and mouse_y positions are also scaled like this:
mouse_x = ev.mouse.x / display_transform_double;
mouse_y = ev.mouse.y / display_transform_double;
Detecting window move
Because no events are triggered when the display window is moved, I had to detect it myself.
Every frame, in the function 'proc_controllers()', I compare the display's window position to the stored values.
If they differ, I call 'proc_screen_change()' with the new values.
if (!fullscreen) // detect if window was moved
{
int x, y;
al_get_window_position(display, &x, &y);
if ((x != disp_x_curr) || (y != disp_y_curr))
proc_screen_change(disp_w_curr, disp_h_curr, x, y, fullscreen);
}