Skip to content

Instantly share code, notes, and snippets.

@abihf
Last active August 29, 2015 14:24
Show Gist options
  • Save abihf/22cd0ab76226bdd2488f to your computer and use it in GitHub Desktop.
Save abihf/22cd0ab76226bdd2488f to your computer and use it in GitHub Desktop.
Boot Splash Animation for 1366x768 computer
// do what dafuq you want to this fuckin shit
// but some code taken from psplash
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <stdint.h>
#include <string.h>
#include <termios.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/fb.h>
#include <linux/vt.h>
#include <linux/kd.h>
#define FADE_IN_STEPS 40
#define LOADER_Y_OFFSET 710
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
} _pixel;
int fbfd = 0;
long int screensize = 0;
unsigned char *fbp = 0;
_pixel splash[768][1366];
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
sem_t sem;
int console_fd = -1;
int vt_visible = 1;
int vtnum = 7;
int running = 1;
void ssplash_fb_set_pixel(char *fbp, int x, int y, unsigned char r, unsigned char g, unsigned char b) {
long int location = 0;
while (!vt_visible && running) {
//printf("waiting semaphore\n");
usleep(1000);
}
if (!running) return;
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
(y+vinfo.yoffset) * finfo.line_length;
if (vinfo.bits_per_pixel == 32) {
*(fbp + location) = b; // Some blue
*(fbp + location + 1) = g; // A little green
*(fbp + location + 2) = r; // A lot of red
*(fbp + location + 3) = 0; // No transparency
}
}
void ssplash_animate_fade_in() {
unsigned char *screenbuffer = 0;
unsigned char dark;
int i, x, y;
screenbuffer = (unsigned char *)malloc(screensize);
if ((int)screenbuffer == -1) {
perror("Error: failed allocate buffer");
exit(4);
}
memset(screenbuffer, 0, screensize);
memcpy(fbp, screenbuffer, screensize);
usleep(200000);
for (i=FADE_IN_STEPS/4; i<=FADE_IN_STEPS && running; i++) {
dark = i==FADE_IN_STEPS ? 0 : 255 - (255 * i / FADE_IN_STEPS);
// Figure out where in memory to put the pixel
for (y = 0; y < vinfo.yres; y++) {
for (x = 0; x < vinfo.xres; x++) {
ssplash_fb_set_pixel(screenbuffer, x, y,
splash[y][x].r > dark ? splash[y][x].r - dark : 0,
splash[y][x].g > dark ? splash[y][x].g - dark : 0,
splash[y][x].b > dark ? splash[y][x].b - dark : 0
/* r > 0 ? r : 0,*/
/* g > 0 ? g : 0,*/
/* b > 0 ? b : 0*/
);
}
}
memcpy(fbp, screenbuffer, screensize);
usleep(15000);
}
free(screenbuffer);
}
void ssplash_animate_loading() {
int steps = 0;
int i, x, y, xoffset;
while(running) {
for (i=0; i<5; i++) {
xoffset = 638 + i * 20;
for (y = 0; y < 3; y++) {
for(x=0; x < 10; x++) {
if (i == steps) {
ssplash_fb_set_pixel(fbp, xoffset + x, LOADER_Y_OFFSET + y,
150, 150, 150);
} else {
ssplash_fb_set_pixel(fbp, xoffset + x, LOADER_Y_OFFSET + y,
splash[LOADER_Y_OFFSET + y][xoffset + x].r,
splash[LOADER_Y_OFFSET + y][xoffset + x].g,
splash[LOADER_Y_OFFSET + y][xoffset + x].b);
}
}
}
}
usleep(400000);
steps = (steps + 1) % 5;
}
}
static void
ssplash_vt_request (int sig)
{
if (vt_visible)
{
/* Allow Switch Away */
if (ioctl (console_fd, VT_RELDISP, 1) < 0)
perror("Error cannot switch away from console");
vt_visible = 0;
/* FIXME:
* We likely now want to signal the main loop as to exit
* and we've now likely switched to the X tty. Note, this
* seems to happen anyway atm due to select() call getting
* a signal interuption error - not sure if this is really
* reliable however.
*/
}
else
{
if (ioctl (console_fd, VT_RELDISP, VT_ACKACQ))
perror ("Error can't acknowledge VT switch");
vt_visible = 1;
/* FIXME: need to schedule repaint some how ? */
}
}
static void
ssplash_console_handle_switches (void)
{
struct sigaction act;
struct vt_mode vt_mode;
if (ioctl(console_fd, VT_GETMODE, &vt_mode) < 0)
{
perror("Error VT_SETMODE failed");
return;
}
act.sa_handler = ssplash_vt_request ;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGUSR1, &act, 0);
vt_mode.mode = VT_PROCESS;
vt_mode.relsig = SIGUSR1;
vt_mode.acqsig = SIGUSR1;
if (ioctl(console_fd, VT_SETMODE, &vt_mode) < 0)
perror("Error VT_SETMODE failed");
}
static void
ssplash_console_ignore_switches (void)
{
struct sigaction act;
struct vt_mode vt_mode;
if (ioctl(console_fd, VT_GETMODE, &vt_mode) < 0)
{
perror("Error VT_SETMODE failed");
return;
}
act.sa_handler = SIG_IGN;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGUSR1, &act, 0);
vt_mode.mode = VT_AUTO;
vt_mode.relsig = 0;
vt_mode.acqsig = 0;
if (ioctl(console_fd, VT_SETMODE, &vt_mode) < 0)
perror("Error VT_SETMODE failed");
}
void ssplash_console_switch() {
char vtname[10];
struct vt_stat vt_state;
sprintf(vtname, "/dev/tty%d", vtnum);
if ((console_fd = open(vtname, O_RDWR |O_NDELAY)) < 0) {
perror("Unable to open vt");
}
ssplash_console_ignore_switches();
if (ioctl(console_fd, VT_ACTIVATE, vtnum) != 0)
perror("Error VT_ACTIVATE failed");
if (ioctl(console_fd, VT_WAITACTIVE, vtnum) != 0)
perror("Error VT_WAITACTIVE failed\n");
ssplash_console_handle_switches ();
if (ioctl(console_fd, KDSETMODE, KD_GRAPHICS) < 0)
perror("Error KDSETMODE KD_GRAPHICS failed\n");
}
void ssplash_console_clean() {
int fd;
ioctl(console_fd, KDSETMODE, KD_TEXT);
ssplash_console_ignore_switches();
close(console_fd);
if ((fd = open ("/dev/tty0", O_RDWR | O_NDELAY, 0)) >= 0) {
ioctl (fd, VT_DISALLOCATE, vtnum);
close (fd);
}
}
void ssplash_exit(int signum) {
running = 0;
ssplash_console_clean();
if (fbp)
munmap(fbp, screensize);
if (fbfd)
close(fbfd);
}
int main(int argc, char **argv)
{
char *buf = &splash;
ssize_t len = 0, total_len = 0;
while ((len = read(STDIN_FILENO, buf, sizeof(splash) - total_len)) > 0) {
buf += len;
total_len += len;
}
if (len < 0) {
perror("unable to read input file");
return 1;
}
else if (total_len == 0) {
printf("Usage: splash < filename.dat\n");
return 0;
}
else if (total_len != sizeof(splash)) {
printf("invalid file size (%d/%d)\n", len, sizeof(splash));
return 1;
}
sem_init(&sem, 0, 0);
signal(SIGHUP, ssplash_exit);
signal(SIGINT, ssplash_exit);
signal(SIGQUIT, ssplash_exit);
ssplash_console_switch();
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (fbfd == -1) {
perror("Error: cannot open framebuffer device");
exit(1);
}
//printf("The framebuffer device was opened successfully.\n");
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
exit(2);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
exit(3);
}
//printf("%dx%d, %dbpp %d\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel, finfo.line_length);
// Figure out the size of the screen in bytes
screensize = finfo.line_length * vinfo.yres;
fbp = (unsigned char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if ((int)fbp == -1) {
perror("Error: failed to map framebuffer device to memory");
exit(4);
}
ssplash_animate_fade_in();
ssplash_animate_loading();
sem_post(&sem);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment