[retro-gtk] Add RetroPixdata
- From: Adrien Plazas <aplazas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [retro-gtk] Add RetroPixdata
- Date: Thu, 12 Oct 2017 14:12:13 +0000 (UTC)
commit de0a7789e9a7de0d405edc366145e94b9332d14b
Author: Adrien Plazas <kekun plazas laposte net>
Date: Thu Oct 12 15:52:42 2017 +0200
Add RetroPixdata
This will be used in the next commit to simplify handling of the core's
video output.
retro-gtk/Makefile.am | 3 +
retro-gtk/retro-pixdata-private.h | 36 ++++
retro-gtk/retro-pixdata.c | 320 +++++++++++++++++++++++++++++++++++++
retro-gtk/retro-pixdata.h | 30 ++++
4 files changed, 389 insertions(+), 0 deletions(-)
---
diff --git a/retro-gtk/Makefile.am b/retro-gtk/Makefile.am
index 5a8116b..4f91e5d 100644
--- a/retro-gtk/Makefile.am
+++ b/retro-gtk/Makefile.am
@@ -45,6 +45,7 @@ retro_gtk_public_h_sources = \
retro-module-iterator.h \
retro-module-query.h \
retro-mouse-id.h \
+ retro-pixdata.h \
retro-pixel-format.h \
retro-pointer-id.h \
retro-rumble-effect.h \
@@ -65,6 +66,7 @@ retro_gtk_private_h_sources = \
retro-option.h \
retro-options.h \
retro-pa-player.h \
+ retro-pixdata-private.h \
retro-rotation.h \
retro-system-av-info.h \
retro-system-info.h \
@@ -96,6 +98,7 @@ libretro_gtk_la_SOURCES = \
retro-option.c \
retro-options.c \
retro-pa-player.c \
+ retro-pixdata.c \
retro-pixel-format.c \
retro-pointer-id.c \
retro-rumble-effect.c \
diff --git a/retro-gtk/retro-pixdata-private.h b/retro-gtk/retro-pixdata-private.h
new file mode 100644
index 0000000..01fe4b7
--- /dev/null
+++ b/retro-gtk/retro-pixdata-private.h
@@ -0,0 +1,36 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#ifndef RETRO_PIXDATA_PRIVATE_H
+#define RETRO_PIXDATA_PRIVATE_H
+
+#if !defined(__RETRO_GTK_INSIDE__) && !defined(RETRO_GTK_COMPILATION)
+# error "Only <retro-gtk.h> can be included directly."
+#endif
+
+#include "retro-pixdata.h"
+
+#include "retro-pixel-format.h"
+
+G_BEGIN_DECLS
+
+struct _RetroPixdata
+{
+ guint8 *data;
+ RetroPixelFormat pixel_format;
+ gsize rowstride;
+ gsize width;
+ gsize height;
+ gfloat aspect_ratio;
+};
+
+void retro_pixdata_init (RetroPixdata *self,
+ gconstpointer data,
+ RetroPixelFormat pixel_format,
+ gsize rowstride,
+ gsize width,
+ gsize height,
+ gfloat aspect_ratio);
+
+G_END_DECLS
+
+#endif /* RETRO_PIXDATA_PRIVATE_H */
diff --git a/retro-gtk/retro-pixdata.c b/retro-gtk/retro-pixdata.c
new file mode 100644
index 0000000..244fe85
--- /dev/null
+++ b/retro-gtk/retro-pixdata.c
@@ -0,0 +1,320 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#include "retro-pixdata-private.h"
+
+G_DEFINE_BOXED_TYPE (RetroPixdata, retro_pixdata, retro_pixdata_copy, retro_pixdata_free)
+
+/*
+ * Because gdk-pixbuf saves dpi as integer we have to multiply it by big enough
+ * number to represent aspect ratio precisely.
+ */
+#define RETRO_CAIRO_DISPLAY_Y_DPI (1000000.0f)
+
+/* Private */
+
+typedef struct {
+ guint16 b: 5;
+ guint16 g: 5;
+ guint16 r: 5;
+ guint16 x: 1;
+} xrgb1555;
+
+typedef struct {
+ guint32 b: 8;
+ guint32 g: 8;
+ guint32 r: 8;
+ guint32 x: 8;
+} xrgb8888;
+
+typedef struct {
+ guint16 b: 5;
+ guint16 g: 6;
+ guint16 r: 5;
+} rgb565;
+
+typedef struct {
+ guint32 a: 8;
+ guint32 b: 8;
+ guint32 g: 8;
+ guint32 r: 8;
+} rgba8888;
+
+typedef rgba8888 (*GetRGBA8888) (gconstpointer pixel);
+
+static rgba8888
+rgba8888_from_xrgb1555 (gconstpointer data)
+{
+ xrgb1555 pixel = *(const xrgb1555 *) data;
+
+ return (rgba8888) {
+ pixel.r << 3 | pixel.r >> 2,
+ pixel.g << 3 | pixel.g >> 2,
+ pixel.b << 3 | pixel.b >> 2,
+ 0xff,
+ };
+}
+
+static rgba8888
+rgba8888_from_xrgb8888 (gconstpointer data)
+{
+ xrgb8888 pixel = *(const xrgb8888 *) data;
+
+ return (rgba8888) {
+ pixel.r,
+ pixel.g,
+ pixel.b,
+ 0xff,
+ };
+}
+
+static rgba8888
+rgba8888_from_rgb565 (gconstpointer data)
+{
+ rgb565 pixel = *(const rgb565 *) data;
+
+ return (rgba8888) {
+ pixel.r << 3 | pixel.r >> 2,
+ pixel.g << 2 | pixel.g >> 4,
+ pixel.b << 3 | pixel.b >> 2,
+ 0xff,
+ };
+}
+
+static gboolean
+get_interface_for_pixel_format (gint pixel_format,
+ GetRGBA8888 *get_pixel,
+ gsize *pixel_size)
+{
+ switch (pixel_format) {
+ case RETRO_PIXEL_FORMAT_XRGB1555:
+ *get_pixel = rgba8888_from_xrgb1555;
+ *pixel_size = sizeof (xrgb1555);
+
+ return TRUE;
+ case RETRO_PIXEL_FORMAT_XRGB8888:
+ *get_pixel = rgba8888_from_xrgb8888;
+ *pixel_size = sizeof (rgba8888);
+
+ return TRUE;
+ case RETRO_PIXEL_FORMAT_RGB565:
+ *get_pixel = rgba8888_from_rgb565;
+ *pixel_size = sizeof (rgb565);
+
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/*
+ * The destination buffer must be at least `height * width * sizeof (rgba8888)`
+ * bytes long.
+ */
+static void
+rgba8888_from_video (gconstpointer src,
+ rgba8888 *dst,
+ size_t pixel_size,
+ guint width,
+ guint height,
+ gsize pitch,
+ GetRGBA8888 get_pixel)
+{
+ gsize row, src_row, dst_row, col, src_col;
+
+ for (row = 0 ; row < height ; row++) {
+ src_row = row * pitch;
+ dst_row = row * width;
+
+ for (col = 0 ; col < width ; col++) {
+ src_col = col * pixel_size;
+
+ dst[dst_row + col] = get_pixel (src_row + src_col + src);
+ }
+ }
+}
+
+static void
+pixels_free (guchar *pixels,
+ gpointer data)
+{
+ g_free (pixels);
+}
+
+/**
+ * retro_pixdata_new:
+ * @data: the video data
+ * @width: the width
+ * @height: the height
+ * @pitch: the distance in bytes between rows
+ * @pixel_format: the pixel format
+ * @aspect_ratio: the aspect ratio to render the video
+ *
+ * Creates a new #RetroPixdata.
+ *
+ * Returns: (transfer full): a new #RetroPixdata, use retro_pixdata_free() to
+ * free it
+ */
+static RetroPixdata *
+retro_pixdata_new (gconstpointer data,
+ RetroPixelFormat pixel_format,
+ gsize rowstride,
+ gsize width,
+ gsize height,
+ gfloat aspect_ratio)
+{
+ RetroPixdata *self;
+
+ g_return_val_if_fail (data != NULL, NULL);
+ g_return_val_if_fail (rowstride != 0, NULL);
+ g_return_val_if_fail (width != 0, NULL);
+ g_return_val_if_fail (height != 0, NULL);
+ g_return_val_if_fail (aspect_ratio > 0.f, NULL);
+
+ self = g_slice_new0 (RetroPixdata);
+ self->data = g_memdup (data, rowstride * height);
+ self->pixel_format = pixel_format;
+ self->rowstride = rowstride;
+ self->width = width;
+ self->height = height;
+ self->aspect_ratio = aspect_ratio;
+
+ return self;
+}
+
+/* Public */
+
+/**
+ * retro_pixdata_init:
+ * @self: a #RetroPixdata
+ * @data: the video data
+ * @width: the width
+ * @height: the height
+ * @pitch: the distance in bytes between rows
+ * @pixel_format: the pixel format
+ * @aspect_ratio: the aspect ratio to render the video
+ *
+ * Initializes @self with the given parameters.
+ */
+void
+retro_pixdata_init (RetroPixdata *self,
+ gconstpointer data,
+ RetroPixelFormat pixel_format,
+ gsize rowstride,
+ gsize width,
+ gsize height,
+ gfloat aspect_ratio)
+{
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (rowstride != 0);
+ g_return_if_fail (width != 0);
+ g_return_if_fail (height != 0);
+ g_return_if_fail (aspect_ratio > 0.f);
+
+ self->data = (guint8 *) data;
+ self->pixel_format = pixel_format;
+ self->rowstride = rowstride;
+ self->width = width;
+ self->height = height;
+ self->aspect_ratio = aspect_ratio;
+}
+
+/**
+ * retro_pixdata_copy:
+ * @self: a #RetroPixdata
+ *
+ * Copies @self into a new #RetroPixdata.
+ *
+ * Returns: (transfer full): a new #RetroPixdata, use retro_pixdata_free() to
+ * free it
+ */
+RetroPixdata *
+retro_pixdata_copy (RetroPixdata *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return retro_pixdata_new (self->data, self->pixel_format,
+ self->rowstride, self->width, self->height,
+ self->aspect_ratio);
+}
+
+/**
+ * retro_pixdata_free:
+ * @self: a #RetroPixdata
+ *
+ * Frees the given #RetroPixdata object.
+ */
+void
+retro_pixdata_free (RetroPixdata *self)
+{
+ g_return_if_fail (self != NULL);
+
+ g_slice_free (RetroPixdata, self);
+}
+
+/**
+ * retro_pixdata_get_aspect_ratio:
+ * @self: a #RetroCore
+ *
+ * Gets the aspect ratio the video should be rendered with.
+ *
+ * Returns: the aspect ratio
+ */
+gfloat
+retro_pixdata_get_aspect_ratio (RetroPixdata *self)
+{
+ g_return_val_if_fail (self != NULL, 0.f);
+
+ return self->aspect_ratio;
+}
+
+/**
+ * retro_pixdata_to_pixbuf:
+ * @self: the #RetroPixdata
+ *
+ * Creates a new #GdkPixbuf from @self.
+ *
+ * Returns: (transfer full): a new #RetroPixdata
+ */
+GdkPixbuf *
+retro_pixdata_to_pixbuf (RetroPixdata *self)
+{
+ GetRGBA8888 get_pixel;
+ gsize pixel_size;
+ rgba8888 *rgba8888_data;
+ GdkPixbuf *pixbuf;
+ gfloat x_dpi;
+ gchar *x_dpi_string;
+ gchar *y_dpi_string;
+
+ g_return_val_if_fail (self != NULL, NULL);
+
+ if (!get_interface_for_pixel_format (self->pixel_format,
+ &get_pixel,
+ &pixel_size))
+ return NULL;
+
+ rgba8888_data = g_new (rgba8888, self->width * self->height);
+ rgba8888_from_video (self->data, rgba8888_data, pixel_size,
+ self->width, self->height, self->rowstride,
+ get_pixel);
+
+ if (rgba8888_data == NULL)
+ return NULL;
+
+ pixbuf = gdk_pixbuf_new_from_data ((guchar *) rgba8888_data,
+ GDK_COLORSPACE_RGB, TRUE, 8,
+ self->width, self->height,
+ self->width * sizeof (rgba8888),
+ pixels_free, NULL);
+
+ x_dpi = self->aspect_ratio * RETRO_CAIRO_DISPLAY_Y_DPI;
+ x_dpi_string = g_strdup_printf ("%g", x_dpi);
+ y_dpi_string = g_strdup_printf ("%g", RETRO_CAIRO_DISPLAY_Y_DPI);
+ gdk_pixbuf_set_option (pixbuf, "x-dpi", x_dpi_string);
+ gdk_pixbuf_set_option (pixbuf, "y-dpi", y_dpi_string);
+ g_free (y_dpi_string);
+ g_free (x_dpi_string);
+
+ return pixbuf;
+}
diff --git a/retro-gtk/retro-pixdata.h b/retro-gtk/retro-pixdata.h
new file mode 100644
index 0000000..3c23057
--- /dev/null
+++ b/retro-gtk/retro-pixdata.h
@@ -0,0 +1,30 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#ifndef RETRO_PIXDATA_H
+#define RETRO_PIXDATA_H
+
+#if !defined(__RETRO_GTK_INSIDE__) && !defined(RETRO_GTK_COMPILATION)
+# error "Only <retro-gtk.h> can be included directly."
+#endif
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define RETRO_TYPE_PIXDATA (retro_pixdata_get_type())
+
+GType retro_pixdata_get_type (void) G_GNUC_CONST;
+
+typedef struct _RetroPixdata RetroPixdata;
+
+RetroPixdata *retro_pixdata_copy (RetroPixdata *self);
+void retro_pixdata_free (RetroPixdata *self);
+gfloat retro_pixdata_get_aspect_ratio (RetroPixdata *self);
+GdkPixbuf *retro_pixdata_to_pixbuf (RetroPixdata *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (RetroPixdata, retro_pixdata_free)
+
+G_END_DECLS
+
+#endif /* RETRO_PIXDATA_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]