* bitmaps. Also uses alpha blending to create a real-time flash
* effect (likely not visible with displays using memory bitmaps as it
* is too slow).
*/
#include <stdio.h>
#include <math.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include "common.c"
#ifdef ALLEGRO_MSVC
#define snprintf _snprintf
#endif
static ALLEGRO_BITMAP *logo, *logo_flash;
static int logo_x, logo_y;
static ALLEGRO_FONT *font;
static int cursor;
static int selection;
static bool regenerate = 0, editing = 0;
static ALLEGRO_CONFIG *config;
static ALLEGRO_COLOR white;
static double anim;
static float clamp(float x)
{
if (x < 0)
return 0;
if (x > 1)
return 1;
return x;
}
static char const *param_names[] = {
"text", "font", "size", "shadow", "blur", "factor", "red", "green",
"blue", NULL
};
* you need to obtain the non-free "Utopia Regular Italic" font. Then
* replace "DejaVuSans.ttf" with "putri.pfa" below.
*/
static char param_values[][256] = {
"Allegro", "data/DejaVuSans.ttf", "140", "10", "2", "0.5", "1.1",
"1.5", "5"
};
* The bitmap will have screen size. If 'bumpmap' is not NULL, it will
* contain another bitmap which is a white, blurred mask of the logo
* which we use for the flash effect.
*/
static ALLEGRO_BITMAP *generate_logo(char const *text,
char const *fontname,
int font_size,
float shadow_offset,
float blur_radius,
float blur_factor,
float light_red,
float light_green,
float light_blue,
ALLEGRO_BITMAP **bumpmap)
{
ALLEGRO_COLOR transparent = al_map_rgba_f(0, 0, 0, 0);
int xp, yp, w, h, i, j, x, y, br, bw, dw, dh;
ALLEGRO_COLOR c;
ALLEGRO_FONT *logofont;
ALLEGRO_STATE state;
ALLEGRO_BITMAP *blur, *light, *logo;
int left, right, top, bottom;
float cx, cy;
dw = al_get_bitmap_width(al_get_target_bitmap());
dh = al_get_bitmap_height(al_get_target_bitmap());
cx = dw * 0.5;
cy = dh * 0.5;
logofont = al_load_font(fontname, -font_size, 0);
al_get_text_dimensions(logofont, text, &xp, &yp, &w, &h);
al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP | ALLEGRO_STATE_BLENDER);
blur = al_create_bitmap(dw, dh);
al_set_target_bitmap(blur);
al_clear_to_color(transparent);
br = blur_radius;
bw = br * 2 + 1;
c = al_map_rgba_f(1, 1, 1, 1.0 / (bw * bw * blur_factor));
al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA,
ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE);
for (i = -br; i <= br; i++) {
for (j = -br; j <= br; j++) {
al_draw_text(logofont, c,
cx - xp * 0.5 - w * 0.5 + i,
cy - yp * 0.5 - h * 0.5 + j, 0, text);
}
}
left = cx - xp * 0.5 - w * 0.5 - br + xp;
top = cy - yp * 0.5 - h * 0.5 - br + yp;
right = left + w + br * 2;
bottom = top + h + br * 2;
if (left < 0)
left = 0;
if (top < 0)
top = 0;
if (right > dw - 1)
right = dw - 1;
if (bottom > dh - 1)
bottom = dh - 1;
light = al_create_bitmap(dw, dh);
al_set_target_bitmap(light);
al_clear_to_color(transparent);
al_lock_bitmap(blur, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY);
al_lock_bitmap_region(light, left, top,
1 + right - left, 1 + bottom - top,
ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY);
for (y = top; y <= bottom; y++) {
for (x = left; x <= right; x++) {
float r1, g1, b1, a1;
float r2, g2, b2, a2;
float r, g, b, a;
float d;
ALLEGRO_COLOR c = al_get_pixel(blur, x, y);
ALLEGRO_COLOR c1 = al_get_pixel(blur, x - 1, y - 1);
ALLEGRO_COLOR c2 = al_get_pixel(blur, x + 1, y + 1);
al_unmap_rgba_f(c, &r, &g, &b, &a);
al_unmap_rgba_f(c1, &r1, &g1, &b1, &a1);
al_unmap_rgba_f(c2, &r2, &g2, &b2, &a2);
d = r2 - r1 + 0.5;
r = clamp(d * light_red);
g = clamp(d * light_green);
b = clamp(d * light_blue);
c = al_map_rgba_f(r, g, b, a);
al_put_pixel(x, y, c);
}
}
al_unlock_bitmap(light);
al_unlock_bitmap(blur);
if (bumpmap)
*bumpmap = blur;
else
al_destroy_bitmap(blur);
logo = al_create_bitmap(dw, dh);
al_set_target_bitmap(logo);
al_clear_to_color(transparent);
c = al_map_rgba_f(0, 0, 0, 0.5 / 9);
al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA,
ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE);
for (i = -1; i <= 1; i++)
for (j = -1; j <= 1; j++)
al_draw_text(logofont, c,
cx - xp * 0.5 - w * 0.5 + shadow_offset + i,
cy - yp * 0.5 - h * 0.5 + shadow_offset + j,
0, text);
al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA,
ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
al_draw_bitmap(light, 0, 0, 0);
al_destroy_bitmap(light);
al_restore_state(&state);
al_destroy_font(logofont);
return logo;
}
static void draw_background(void)
{
ALLEGRO_COLOR c[2];
int i, j;
c[0] = al_map_rgba(0xaa, 0xaa, 0xaa, 0xff);
c[1] = al_map_rgba(0x99, 0x99, 0x99, 0xff);
for (i = 0; i < 640 / 16; i++) {
for (j = 0; j < 480 / 16; j++) {
al_draw_filled_rectangle(i * 16, j * 16,
i * 16 + 16, j * 16 + 16,
c[(i + j) & 1]);
}
}
}
static void print_parameters(void)
{
int i;
ALLEGRO_STATE state;
ALLEGRO_COLOR normal = al_map_rgba_f(0, 0, 0, 1);
ALLEGRO_COLOR light = al_map_rgba_f(0, 0, 1, 1);
ALLEGRO_COLOR label = al_map_rgba_f(0.2, 0.2, 0.2, 1);
int th;
al_store_state(&state, ALLEGRO_STATE_BLENDER);
th = al_get_font_line_height(font) + 3;
for (i = 0; param_names[i]; i++) {
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
al_draw_textf(font, label, 2, 2 + i * th, 0, "%s", param_names[i]);
}
for (i = 0; param_names[i]; i++) {
int y = 2 + i * th;
al_draw_filled_rectangle(75, y, 375, y + th - 2,
al_map_rgba_f(0.5, 0.5, 0.5, 0.5));
al_draw_textf(font, i == selection ? light : normal, 75, y, 0, "%s", param_values[i]);
if (i == selection && editing &&
(((int)(al_get_time() * 2)) & 1)) {
int x = 75 + al_get_text_width(font, param_values[i]);
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
al_draw_line(x, y, x, y + th, white, 0);
}
}
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
al_draw_textf(font, normal, 400, 2, 0, "%s", "R - Randomize");
al_draw_textf(font, normal, 400, 2 + th, 0, "%s", "S - Save as logo.png");
al_draw_textf(font, normal, 2, 480 - th * 2 - 2, 0, "%s",
"To modify, press Return, then enter value, "
"then Return again.");
al_draw_textf(font, normal, 2, 480 - th - 2, 0, "%s",
"Use cursor up/down to "
"select the value to modify.");
al_restore_state(&state);
}
static char const *rnum(float min, float max)
{
static char s[256];
double x = rand() / (double)RAND_MAX;
x = min + x * (max - min);
snprintf(s, sizeof s, "%.1f", x);
return s;
}
static void randomize(void)
{
strcpy(param_values[3], rnum(2, 12));
strcpy(param_values[4], rnum(1, 8));
strcpy(param_values[5], rnum(0.1, 1));
strcpy(param_values[6], rnum(0, 5));
strcpy(param_values[7], rnum(0, 5));
strcpy(param_values[8], rnum(0, 5));
regenerate = true;
}
static void save(void)
{
al_save_bitmap("logo.png", logo);
}
static void mouse_click(int x, int y)
{
int th = al_get_font_line_height(font) + 3;
int sel = (y - 2) / th;
int i;
if (x < 400) {
for (i = 0; param_names[i]; i++) {
if (sel == i) {
selection = i;
cursor = 0;
editing = true;
}
}
}
else if (x < 500) {
if (sel == 0)
randomize();
if (sel == 1)
save();
}
}
static void render(void)
{
double t = al_get_time();
if (regenerate) {
al_destroy_bitmap(logo);
al_destroy_bitmap(logo_flash);
logo = NULL;
regenerate = false;
}
if (!logo) {
ALLEGRO_BITMAP *fullflash;
ALLEGRO_BITMAP *fulllogo = generate_logo(param_values[0],
param_values[1],
strtol(param_values[2], NULL, 10),
strtod(param_values[3], NULL),
strtod(param_values[4], NULL),
strtod(param_values[5], NULL),
strtod(param_values[6], NULL),
strtod(param_values[7], NULL),
strtod(param_values[8], NULL),
&fullflash);
ALLEGRO_BITMAP *crop;
int x, y, left = 640, top = 480, right = -1, bottom = -1;
al_lock_bitmap(fulllogo, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY);
for (y = 0; y < 480; y++) {
for (x = 0; x < 640; x++) {
ALLEGRO_COLOR c = al_get_pixel(fulllogo, x, y);
float r, g, b, a;
al_unmap_rgba_f(c, &r, &g, &b, &a);
if (a > 0) {
if (x < left)
left = x;
if (y < top)
top = y;
if (x > right)
right = x;
if (y > bottom)
bottom = y;
}
}
}
al_unlock_bitmap(fulllogo);
if (left == 640)
left = 0;
if (top == 480)
top = 0;
if (right < left)
right = left;
if (bottom < top)
bottom = top;
crop = al_create_sub_bitmap(fulllogo, left, top,
1 + right - left, 1 + bottom - top);
logo = al_clone_bitmap(crop);
al_destroy_bitmap(crop);
al_destroy_bitmap(fulllogo);
crop = al_create_sub_bitmap(fullflash, left, top,
1 + right - left, 1 + bottom - top);
logo_flash = al_clone_bitmap(crop);
al_destroy_bitmap(crop);
al_destroy_bitmap(fullflash);
logo_x = left;
logo_y = top;
anim = t;
}
draw_background();
if (t - anim < 0.5) {
ALLEGRO_STATE state;
int i, j;
float f = sin(ALLEGRO_PI * ((t - anim) / 0.5));
ALLEGRO_COLOR c = al_map_rgb_f(f * 0.3, f * 0.3, f * 0.3);
al_store_state(&state, ALLEGRO_STATE_BLENDER);
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
al_draw_tinted_bitmap(logo, al_map_rgba_f(1, 1, 1, 1 - f), logo_x, logo_y, 0);
al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ONE);
for (j = -2; j <= 2; j += 2) {
for (i = -2; i <= 2; i += 2) {
al_draw_tinted_bitmap(logo_flash, c, logo_x + i, logo_y + j, 0);
}
}
al_restore_state(&state);
}
else
al_draw_bitmap(logo, logo_x, logo_y, 0);
print_parameters();
}
int main(int argc, char **argv)
{
ALLEGRO_DISPLAY *display;
ALLEGRO_TIMER *timer;
ALLEGRO_EVENT_QUEUE *queue;
int redraw = 0, i;
bool quit = false;
(void)argc;
(void)argv;
if (!al_init()) {
abort_example("Could not initialise Allegro\n");
}
al_init_primitives_addon();
al_install_mouse();
al_init_image_addon();
al_init_font_addon();
al_init_ttf_addon();
init_platform_specific();
srand(time(NULL));
white = al_map_rgba_f(1, 1, 1, 1);
display = al_create_display(640, 480);
if (!display) {
abort_example("Could not create display\n");
}
al_set_window_title(display, "Allegro Logo Generator");
al_install_keyboard();
config = al_load_config_file("logo.ini");
if (!config)
config = al_create_config();
for (i = 0; param_names[i]; i++) {
char const *value = al_get_config_value(config, "logo", param_names[i]);
if (value)
strncpy(param_values[i], value, sizeof(param_values[i]));
}
font = al_load_font("data/DejaVuSans.ttf", 12, 0);
if (!font) {
abort_example("Could not load font\n");
}
timer = al_create_timer(1.0 / 60);
queue = al_create_event_queue();
al_register_event_source(queue, al_get_keyboard_event_source());
al_register_event_source(queue, al_get_mouse_event_source());
al_register_event_source(queue, al_get_display_event_source(display));
al_register_event_source(queue, al_get_timer_event_source(timer));
al_start_timer(timer);
while (!quit) {
ALLEGRO_EVENT event;
al_wait_for_event(queue, &event);
if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
break;
if (event.type == ALLEGRO_EVENT_KEY_CHAR) {
if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
quit = true;
}
else if (event.keyboard.keycode == ALLEGRO_KEY_ENTER) {
if (editing) {
regenerate = true;
editing = false;
}
else {
cursor = strlen(param_values[selection]);
editing = true;
}
}
else if (event.keyboard.keycode == ALLEGRO_KEY_UP) {
if (selection > 0) {
selection--;
cursor = strlen(param_values[selection]);
editing = false;
}
}
else if (event.keyboard.keycode == ALLEGRO_KEY_DOWN) {
if (param_names[selection + 1]) {
selection++;
cursor = strlen(param_values[selection]);
editing = false;
}
}
else {
int c = event.keyboard.unichar;
if (editing) {
if (event.keyboard.keycode == ALLEGRO_KEY_BACKSPACE) {
if (cursor > 0) {
ALLEGRO_USTR *u = al_ustr_new(param_values[selection]);
if (al_ustr_prev(u, &cursor)) {
al_ustr_remove_chr(u, cursor);
strncpy(param_values[selection], al_cstr(u),
sizeof param_values[selection]);
}
al_ustr_free(u);
}
}
else if (c >= 32) {
ALLEGRO_USTR *u = al_ustr_new(param_values[selection]);
cursor += al_ustr_set_chr(u, cursor, c);
al_ustr_set_chr(u, cursor, 0);
strncpy(param_values[selection], al_cstr(u),
sizeof param_values[selection]);
al_ustr_free(u);
}
}
else {
if (c == 'r')
randomize();
if (c == 's')
save();
}
}
}
if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
if (event.mouse.button == 1) {
mouse_click(event.mouse.x, event.mouse.y);
}
}
if (event.type == ALLEGRO_EVENT_TIMER)
redraw++;
if (redraw && al_is_event_queue_empty(queue)) {
redraw = 0;
render();
al_flip_display();
}
}
for (i = 0; param_names[i]; i++) {
al_set_config_value(config, "logo", param_names[i],
param_values[i]);
}
al_save_config_file("logo.ini", config);
al_destroy_config(config);
return 0;
}