diff --git a/message.c b/message.c new file mode 100644 index 0000000000..ad58d4f94d --- /dev/null +++ b/message.c @@ -0,0 +1,147 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010 - Hans-Kristian Arntzen + * + * Some code herein may be based on code found in BSNES. + * + * SSNES is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SSNES. + * If not, see . + */ + +#include "message.h" +#include +#include +#include + +struct queue_elem +{ + unsigned duration; + unsigned prio; + char *msg; +}; + +struct msg_queue +{ + struct queue_elem **elems; + size_t ptr; + size_t size; + char *tmp_msg; +}; + +msg_queue_t *msg_queue_new(size_t size) +{ + msg_queue_t *queue = calloc(1, sizeof(*queue)); + if (!queue) + return NULL; + + queue->size = size + 1; + queue->elems = calloc(queue->size, sizeof(struct queue_elem*)); + // Allocate one extra for scratch space when finding lowest prio elem. + + if (!queue->elems) + { + free(queue); + return NULL; + } + queue->ptr = 1; + return queue; +} + +void msg_queue_free(msg_queue_t *queue) +{ + for (size_t i = 1; i < queue->ptr; i++) + { + if (queue->elems[i]) + { + free(queue->elems[i]->msg); + free(queue->elems[i]); + } + } + free(queue->elems); + free(queue->tmp_msg); + free(queue); +} + +void msg_queue_push(msg_queue_t *queue, const char *msg, unsigned prio, unsigned duration) +{ + struct queue_elem *new_elem = calloc(1, sizeof(struct queue_elem)); + new_elem->prio = prio; + new_elem->duration = duration; + new_elem->msg = msg ? strdup(msg) : NULL; + + queue->elems[queue->ptr] = new_elem; + size_t tmp_ptr = queue->ptr++; + + while (tmp_ptr > 1) + { + struct queue_elem *parent = queue->elems[tmp_ptr >> 1]; + struct queue_elem *child = queue->elems[tmp_ptr]; + + if (child->prio <= parent->prio) + break; + else + { + queue->elems[tmp_ptr >> 1] = child; + queue->elems[tmp_ptr] = parent; + } + tmp_ptr >>= 1; + } +} + +const char *msg_queue_pull(msg_queue_t *queue) +{ + if (queue->ptr == 1) // Nothing in queue. :( + return NULL; + + struct queue_elem *front = queue->elems[1]; + front->duration--; + if (front->duration > 0) + return front->msg; + else + { + queue->tmp_msg = front->msg; + front->msg = NULL; + + struct queue_elem *front = queue->elems[1]; + struct queue_elem *last = queue->elems[--queue->ptr]; + queue->elems[1] = last; + free(front); + + size_t tmp_ptr = 1; + for (;;) + { + bool left = (tmp_ptr * 2 <= queue->ptr) && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]); + bool right = (tmp_ptr * 2 + 1 <= queue->ptr) && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]); + + if (!left && !right) + break; + + size_t switch_index = tmp_ptr; + if (left && !right) + switch_index <<= 1; + else if (right && !left) + switch_index += switch_index + 1; + else + { + if (queue->elems[tmp_ptr * 2] >= queue->elems[tmp_ptr * 2 + 1]) + switch_index <<= 1; + else + switch_index += switch_index + 1; + } + struct queue_elem *parent = queue->elems[tmp_ptr]; + struct queue_elem *child = queue->elems[switch_index]; + queue->elems[tmp_ptr] = child; + queue->elems[switch_index] = parent; + tmp_ptr = switch_index; + } + + return queue->tmp_msg; + } +} diff --git a/message.h b/message.h new file mode 100644 index 0000000000..a5bfca5bcb --- /dev/null +++ b/message.h @@ -0,0 +1,38 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010 - Hans-Kristian Arntzen + * + * Some code herein may be based on code found in BSNES. + * + * SSNES is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SSNES. + * If not, see . + */ + + +#ifndef __SSNES_MSG_QUEUE_H +#define __SSNES_MSG_QUEUE_H + +#include + +typedef struct msg_queue msg_queue_t; + +// Creates a message queue with maximum size different messages. Returns NULL if allocation error. +msg_queue_t *msg_queue_new(size_t size); + +// Higher prio is... higher prio :) Duration is how many times a message can be pulled from queue before it vanishes. (E.g. show a message for 3 seconds @ 60fps = 180 duration). + +void msg_queue_push(msg_queue_t *queue, const char *msg, unsigned prio, unsigned duration); + +// Pulls highest prio message in queue. Returns NULL if no message in queue. +const char *msg_queue_pull(msg_queue_t *queue); + +void msg_queue_free(msg_queue_t *queue); + +#endif