summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--COPYING211
-rw-r--r--Makefile16
-rw-r--r--README3
-rw-r--r--examples/cacaserver.c564
-rw-r--r--examples/opengl3_hello.c199
-rw-r--r--res/eo1.bmpbin0 -> 76822 bytes
-rw-r--r--src/main.c198
-rw-r--r--src/main.h23
-rw-r--r--src/scene00.c73
-rw-r--r--src/scene00.h12
-rw-r--r--src/scene01.c49
-rw-r--r--src/scene01.h12
-rw-r--r--src/scene02.c42
-rw-r--r--src/scene02.h12
15 files changed, 1415 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3d1317d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+demoscene-eo
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..328dff4
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,211 @@
+The libfreefare source code is licensed by the *modified* GNU Lesser
+General Public License (LGPL), text provided below. A special exception
+to the LGPL is included to allow you to distribute a combined work that
+includes the libfreefare without being obliged to provide the source
+code for any proprietary components. The exception text is also included
+at the bottom of this file.
+
+The LGPL license text follows.
+
+------------------------------------------------------------------------
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+
+------------------------------------------------------------------------
+
+The libfreefare LGPL Exception Text:
+
+Any libfreefare source code, whether modified or in it's original
+release form, or whether in whole or in part, can only be distributed by
+you under the terms of the GNU Lesser General Public License plus this
+exception. An independent module is a module which is not derived from
+or based on the libfreefare.
+
+Clause 1:
+
+Linking the libfreefare statically or dynamically with other modules is
+making a combined work based on the libfreefare. Thus, the terms and
+conditions of the GNU Lesser General Public License cover the whole
+combination.
+
+As a special exception, the copyright holder of the libfreefare gives
+you permission to link the libfreefare with independent modules that
+communicate with the libfreefare solely through the libfreefare API
+interface, regardless of the license terms of these independent modules,
+and to copy and distribute the resulting combined work under terms of
+your choice, provided that:
+
+ - Every copy of the combined work is accompanied by a written
+ statement that details to the recipient the version of the
+ libfreefare used and an offer by yourself to provide the libfreefare
+ source code (including any modifications you may have made) should
+ the recipient request it.
+
+ - The independent modules add significant and primary functionality to
+ the libfreefare and do not merely extend the existing functionality
+ already present in the libfreefare.
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..41a09e5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+CFLAGS=-Wall -Werror -g
+PKGLIBS=caca sdl2 glu
+
+all: demoscene-eo
+
+server: demoscene-eo
+ CACA_DRIVER=raw CACA_GEOMETRY=80x25 ./demoscene-eo | cacaserver
+
+demoscene-eo: src/main.c src/main.h $(wildcard src/scene*.[ch]) Makefile
+ pkg-config --libs --cflags $(PKGLIBS)
+ gcc $(CFLAGS) `pkg-config --libs --cflags $(PKGLIBS)` src/main.c $(wildcard src/scene*.c) -o $@
+
+clean:
+ rm -f demoscene-eo
+
+.PHONY=all clean run
diff --git a/README b/README
new file mode 100644
index 0000000..aa92423
--- /dev/null
+++ b/README
@@ -0,0 +1,3 @@
+
+
+apt install libcaca-dev libsdl2-dev libglu1-mesa-dev
diff --git a/examples/cacaserver.c b/examples/cacaserver.c
new file mode 100644
index 0000000..825c3d4
--- /dev/null
+++ b/examples/cacaserver.c
@@ -0,0 +1,564 @@
+/*
+ * cacaserver Colour ASCII-Art library
+ * Copyright (c) 2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ * 2006-2014 Sam Hocevar <sam@hocevar.net>
+ * All Rights Reserved
+ *
+ * This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What the Fuck You Want
+ * to Public License, Version 2, as published by Sam Hocevar. See
+ * http://www.wtfpl.net/ for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#if defined(HAVE_ARPA_INET_H)
+# include <arpa/inet.h>
+#elif defined(HAVE_WINSOCK2_H)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define USE_WINSOCK 1
+#endif
+#if defined(HAVE_NETINET_IN_H)
+# include <netinet/in.h>
+#endif
+#if defined(HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#ifndef USE_WINSOCK
+# define USE_WINSOCK 0
+#endif
+
+#include "caca.h"
+
+#define BACKLOG 1337 /* Number of pending connections */
+#define INBUFFER 32 /* Size of per-client input buffer */
+#define OUTBUFFER 300000 /* Size of per-client output buffer */
+
+/* Following vars are static */
+#define INIT_PREFIX \
+ "\xff\xfb\x01" /* WILL ECHO */ \
+ "\xff\xfb\x03" /* WILL SUPPRESS GO AHEAD */ \
+ "\xff\xfd\x31" /* DO NAWS */ \
+ "\xff\x1f\xfa____" /* SB NAWS */ \
+ "\xff\xf0" /* SE */ \
+ "\033]2;caca for the network\x07" /* Change window title */ \
+ "\033[H\033[J" /* Clear screen */
+ /*"\033[?25l"*/ /* Hide cursor */
+
+#define ANSI_PREFIX \
+ "\033[1;1H" /* move(0,0) */ \
+ "\033[1;1H" /* move(0,0) again */
+
+#define ANSI_RESET \
+ " " /* Garbage */ \
+ "\033[?1049h" /* Clear screen */ \
+ "\033[?1049h" /* Clear screen again */
+
+static char const telnet_commands[16][5] =
+{
+ "SE ", "NOP ", "DM ", "BRK ", "IP ", "AO ", "AYT ", "EC ",
+ "EL ", "GA ", "SB ", "WILL", "WONT", "DO ", "DONT", "IAC "
+};
+
+static char const telnet_options[37][5] =
+{
+ "????", "ECHO", "????", "SUGH", "????", "STTS", "TIMK", "????",
+ "????", "????", "????", "????", "????", "????", "????", "????",
+ "????", "????", "????", "????", "????", "????", "????", "????",
+ "TTYP", "????", "????", "????", "????", "????", "????", "NAWS",
+ "TRSP", "RMFC", "LIMO", "????", "EVAR"
+};
+
+#define COMMAND_NAME(x) (x>=240)?telnet_commands[x-240]:"????"
+#define OPTION_NAME(x) (x<=36)?telnet_options[x]:"????"
+
+struct client
+{
+ int fd;
+ int ready;
+ uint8_t inbuf[INBUFFER];
+ int inbytes;
+ uint8_t outbuf[OUTBUFFER];
+ int start, stop;
+};
+
+struct server
+{
+ unsigned int width, height;
+ unsigned int port;
+ int sockfd;
+ struct sockaddr_in my_addr;
+ socklen_t sin_size;
+
+ /* Input buffer */
+ uint8_t *input;
+ unsigned int read;
+
+ char prefix[sizeof(INIT_PREFIX)];
+
+ caca_canvas_t *canvas;
+ void *buffer;
+ size_t buflen;
+
+ int client_count;
+ struct client *clients;
+
+ RETSIGTYPE (*sigpipe_handler)(int);
+};
+
+static void manage_connections(struct server *server);
+static int send_data(struct server *server, struct client *c);
+ssize_t nonblock_write(int fd, void *buf, size_t len);
+
+int main(void)
+{
+ int i, yes = 1, flags;
+ struct server *server;
+ char *tmp;
+
+#if USE_WINSOCK
+ WORD winsockVersion;
+ WSADATA wsaData;
+ winsockVersion = MAKEWORD(1, 1);
+
+ WSAStartup(winsockVersion, &wsaData);
+#endif
+ server = malloc(sizeof(struct server));
+
+ server->input = malloc(12);
+ server->read = 0;
+
+ server->client_count = 0;
+ server->clients = NULL;
+ server->port = 0xCACA; /* 51914 */
+
+ /* FIXME, handle >255 sizes */
+ memcpy(server->prefix, INIT_PREFIX, sizeof(INIT_PREFIX));
+ tmp = strstr(server->prefix, "____");
+ tmp[0] = (uint8_t) (server->width & 0xff00) >> 8;
+ tmp[1] = (uint8_t) server->width & 0xff;
+ tmp[2] = (uint8_t) (server->height & 0xff00) >> 8;
+ tmp[3] = (uint8_t) server->height & 0xff;
+
+ if((server->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ perror("socket");
+ return -1;
+ }
+
+ if(setsockopt(server->sockfd, SOL_SOCKET,
+ SO_REUSEADDR, &yes, sizeof(int)) == -1)
+ {
+ perror("setsockopt SO_REUSEADDR");
+ return -1;
+ }
+
+ server->my_addr.sin_family = AF_INET;
+ server-> my_addr.sin_port = htons(server->port);
+ server->my_addr.sin_addr.s_addr = INADDR_ANY;
+ memset(&(server->my_addr.sin_zero), '\0', 8);
+
+ if(bind(server->sockfd, (struct sockaddr *)&server->my_addr,
+ sizeof(struct sockaddr)) == -1)
+ {
+ perror("bind");
+ return -1;
+ }
+
+ /* Non blocking socket */
+ flags = fcntl(server->sockfd, F_GETFL, 0);
+ fcntl(server->sockfd, F_SETFL, flags | O_NONBLOCK);
+
+ if(listen(server->sockfd, BACKLOG) == -1)
+ {
+ perror("listen");
+ return -1;
+ }
+
+ server->canvas = caca_create_canvas(0, 0);
+ server->buffer = NULL;
+
+ /* Ignore SIGPIPE */
+ server->sigpipe_handler = signal(SIGPIPE, SIG_IGN);
+
+ fprintf(stderr, "initialised network, listening on port %i\n",
+ server->port);
+
+ /* Main loop */
+ for(;;)
+ {
+restart:
+ /* Manage new connections as this function will be called sometimes
+ * more often than display */
+ manage_connections(server);
+
+ /* Read data from stdin */
+ if(server->read < 12)
+ {
+ read(0, server->input + server->read, 12 - server->read);
+ server->read = 12;
+ }
+
+ while(caca_import_canvas_from_memory(server->canvas, server->input,
+ server->read, "caca") < 0)
+ {
+ memmove(server->input, server->input + 1, server->read - 1);
+ read(0, server->input + server->read - 1, 1);
+ }
+
+ for(;;)
+ {
+ ssize_t needed, wanted;
+
+ needed = caca_import_canvas_from_memory(server->canvas,
+ server->input,
+ server->read, "caca");
+ if(needed < 0)
+ goto restart;
+
+ if(needed > 0)
+ {
+ server->read -= needed;
+ memmove(server->input, server->input + needed, server->read);
+ break;
+ }
+
+ server->input = realloc(server->input, server->read + 128);
+ wanted = read(0, server->input + server->read, 128);
+ if(wanted < 0)
+ goto restart;
+ server->read += wanted;
+ }
+
+ /* Free the previous export buffer, if any */
+ if(server->buffer)
+ {
+ free(server->buffer);
+ server->buffer = NULL;
+ }
+
+ /* Get ANSI representation of the image and skip the end-of buffer
+ * linefeed ("\r\n", 2 byte) */
+ server->buffer = caca_export_canvas_to_memory(server->canvas, "utf8cr",
+ &server->buflen);
+ server->buflen -= 2;
+
+ for(i = 0; i < server->client_count; i++)
+ {
+ if(server->clients[i].fd == -1)
+ continue;
+
+ if(send_data(server, &server->clients[i]))
+ {
+ fprintf(stderr, "[%i] dropped connection\n",
+ server->clients[i].fd);
+ close(server->clients[i].fd);
+ server->clients[i].fd = -1;
+ }
+ }
+ }
+
+ /* Kill all remaining clients */
+ for(i = 0; i < server->client_count; i++)
+ {
+ if(server->clients[i].fd == -1)
+ continue;
+
+ close(server->clients[i].fd);
+ server->clients[i].fd = -1;
+ }
+
+ if(server->buffer)
+ free(server->buffer);
+
+ caca_free_canvas(server->canvas);
+
+ /* Restore SIGPIPE handler */
+ signal(SIGPIPE, server->sigpipe_handler);
+
+ free(server);
+
+#if USE_WINSOCK
+ WSACleanup();
+#endif
+ return 0;
+}
+
+/*
+ * XXX: The following functions are local
+ */
+
+static void manage_connections(struct server *server)
+{
+ int fd, flags;
+ struct sockaddr_in remote_addr;
+ socklen_t len = sizeof(struct sockaddr_in);
+
+ fd = accept(server->sockfd, (struct sockaddr *)&remote_addr, &len);
+ if(fd == -1)
+ return;
+
+ fprintf(stderr, "[%i] connected from %s\n",
+ fd, inet_ntoa(remote_addr.sin_addr));
+
+ /* Non blocking socket */
+ flags = fcntl(fd, F_SETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ if(server->clients == NULL)
+ {
+ server->clients = malloc(sizeof(struct client));
+ if(server->clients == NULL)
+ {
+ close(fd);
+ return;
+ }
+ }
+ else
+ {
+ server->clients = realloc(server->clients,
+ (server->client_count+1) * sizeof(struct client));
+ }
+
+ server->clients[server->client_count].fd = fd;
+ server->clients[server->client_count].ready = 0;
+ server->clients[server->client_count].inbytes = 0;
+ server->clients[server->client_count].start = 0;
+ server->clients[server->client_count].stop = 0;
+
+ /* If we already have data to send, send it to the new client */
+ if(send_data(server, &server->clients[server->client_count]))
+ {
+ fprintf(stderr, "[%i] dropped connection\n", fd);
+ close(fd);
+ server->clients[server->client_count].fd = -1;
+ return;
+ }
+
+ server->client_count++;
+}
+
+static int send_data(struct server *server, struct client *c)
+{
+ ssize_t ret;
+
+ /* Not for us */
+ if(c->fd < 0)
+ return -1;
+
+ /* Listen to incoming data */
+ for(;;)
+ {
+ ret = read(c->fd, c->inbuf + c->inbytes, 1);
+ if(ret <= 0)
+ break;
+
+ c->inbytes++;
+
+ /* Check for telnet sequences */
+ if(c->inbuf[0] == 0xff)
+ {
+ if(c->inbytes == 1)
+ {
+ ;
+ }
+ else if(c->inbuf[1] == 0xfd || c->inbuf[1] == 0xfc)
+ {
+ if(c->inbytes == 3)
+ {
+ fprintf(stderr, "[%i] said: %.02x %.02x %.02x (%s %s %s)\n",
+ c->fd, c->inbuf[0], c->inbuf[1], c->inbuf[2],
+ COMMAND_NAME(c->inbuf[0]), COMMAND_NAME(c->inbuf[1]), OPTION_NAME(c->inbuf[2]));
+ /* Just ignore, lol */
+ c->inbytes = 0;
+ }
+ }
+ else
+ c->inbytes = 0;
+ }
+ else if(c->inbytes == 1)
+ {
+ if(c->inbuf[0] == 0x03)
+ {
+ fprintf(stderr, "[%i] pressed C-c\n", c->fd);
+ return -1; /* User requested to quit */
+ }
+
+ c->inbytes = 0;
+ }
+ }
+
+ /* Send the telnet initialisation commands */
+ if(!c->ready)
+ {
+ ret = nonblock_write(c->fd, server->prefix, sizeof(INIT_PREFIX));
+ if(ret == -1)
+ return (errno == EAGAIN) ? 0 : -1;
+
+ if(ret < (ssize_t)sizeof(INIT_PREFIX))
+ return 0;
+
+ c->ready = 1;
+ }
+
+ /* No error, there's just nothing to send yet */
+ if(!server->buffer)
+ return 0;
+
+ /* If we have backlog, send the backlog */
+ if(c->stop)
+ {
+ ret = nonblock_write(c->fd, c->outbuf + c->start, c->stop - c->start);
+
+ if(ret == -1)
+ {
+ if(errno == EAGAIN)
+ ret = 0;
+ else
+ {
+ fprintf(stderr, "[%i] failed (%s)\n",
+ c->fd, strerror(errno));
+ return -1;
+ }
+ }
+
+ if(ret == c->stop - c->start)
+ {
+ /* We got rid of the backlog! */
+ c->start = c->stop = 0;
+ }
+ else
+ {
+ c->start += ret;
+
+ if(c->stop - c->start + strlen(ANSI_PREFIX) + server->buflen
+ > OUTBUFFER)
+ {
+ /* Overflow! Empty buffer and start again */
+ memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET));
+ c->start = 0;
+ c->stop = strlen(ANSI_RESET);
+ return 0;
+ }
+
+ /* Need to move? */
+ if(c->stop + strlen(ANSI_PREFIX) + server->buflen > OUTBUFFER)
+ {
+ memmove(c->outbuf, c->outbuf + c->start, c->stop - c->start);
+ c->stop -= c->start;
+ c->start = 0;
+ }
+
+ memcpy(c->outbuf + c->stop, ANSI_PREFIX, strlen(ANSI_PREFIX));
+ c->stop += strlen(ANSI_PREFIX);
+ memcpy(c->outbuf + c->stop, server->buffer, server->buflen);
+ c->stop += server->buflen;
+
+ return 0;
+ }
+ }
+
+ /* We no longer have backlog, send our new data */
+
+ /* Send ANSI prefix */
+ ret = nonblock_write(c->fd, ANSI_PREFIX, strlen(ANSI_PREFIX));
+ if(ret == -1)
+ {
+ if(errno == EAGAIN)
+ ret = 0;
+ else
+ {
+ fprintf(stderr, "[%i] failed (%s)\n", c->fd, strerror(errno));
+ return -1;
+ }
+ }
+
+ if(ret < (ssize_t)strlen(ANSI_PREFIX))
+ {
+ if(strlen(ANSI_PREFIX) + server->buflen > OUTBUFFER)
+ {
+ /* Overflow! Empty buffer and start again */
+ memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET));
+ c->start = 0;
+ c->stop = strlen(ANSI_RESET);
+ return 0;
+ }
+
+ memcpy(c->outbuf, ANSI_PREFIX, strlen(ANSI_PREFIX) - ret);
+ c->stop = strlen(ANSI_PREFIX) - ret;
+ memcpy(c->outbuf + c->stop, server->buffer, server->buflen);
+ c->stop += server->buflen;
+
+ return 0;
+ }
+
+ /* Send actual data */
+ ret = nonblock_write(c->fd, server->buffer, server->buflen);
+ if(ret == -1)
+ {
+ if(errno == EAGAIN)
+ ret = 0;
+ else
+ {
+ fprintf(stderr, "[%i] failed (%s)\n", c->fd, strerror(errno));
+ return -1;
+ }
+ }
+
+ if(ret < (int)server->buflen)
+ {
+ if(server->buflen > OUTBUFFER)
+ {
+ /* Overflow! Empty buffer and start again */
+ memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET));
+ c->start = 0;
+ c->stop = strlen(ANSI_RESET);
+ return 0;
+ }
+
+ memcpy(c->outbuf, server->buffer, server->buflen - ret);
+ c->stop = server->buflen - ret;
+
+ return 0;
+ }
+
+ return 0;
+}
+
+ssize_t nonblock_write(int fd, void *buf, size_t len)
+{
+ size_t total = 0;
+ ssize_t ret;
+
+ while(total < len)
+ {
+ do
+ {
+ ret = write(fd, buf, len);
+ }
+ while(ret < 0 && errno == EINTR);
+
+ if(ret < 0)
+ return ret;
+ else if(ret == 0)
+ return total;
+
+ total += len;
+ buf = (void *)((uintptr_t)buf + len);
+ }
+
+ return total;
+}
+
diff --git a/examples/opengl3_hello.c b/examples/opengl3_hello.c
new file mode 100644
index 0000000..7cc9070
--- /dev/null
+++ b/examples/opengl3_hello.c
@@ -0,0 +1,199 @@
+/*
+ Minimal SDL2 + OpenGL3 example.
+
+ Author: https://github.com/koute
+
+ This file is in the public domain; you can do whatever you want with it.
+ In case the concept of public domain doesn't exist in your jurisdiction
+ you can also use this code under the terms of Creative Commons CC0 license,
+ either version 1.0 or (at your option) any later version; for details see:
+ http://creativecommons.org/publicdomain/zero/1.0/
+
+ This software is distributed without any warranty whatsoever.
+
+ Compile and run with: gcc opengl3_hello.c `sdl2-config --libs --cflags` -lGL -Wall && ./a.out
+*/
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <SDL.h>
+#include <SDL_opengl.h>
+
+#include <stdio.h>
+
+typedef float t_mat4x4[16];
+
+static inline void mat4x4_ortho( t_mat4x4 out, float left, float right, float bottom, float top, float znear, float zfar )
+{
+ #define T(a, b) (a * 4 + b)
+
+ out[T(0,0)] = 2.0f / (right - left);
+ out[T(0,1)] = 0.0f;
+ out[T(0,2)] = 0.0f;
+ out[T(0,3)] = 0.0f;
+
+ out[T(1,1)] = 2.0f / (top - bottom);
+ out[T(1,0)] = 0.0f;
+ out[T(1,2)] = 0.0f;
+ out[T(1,3)] = 0.0f;
+
+ out[T(2,2)] = -2.0f / (zfar - znear);
+ out[T(2,0)] = 0.0f;
+ out[T(2,1)] = 0.0f;
+ out[T(2,3)] = 0.0f;
+
+ out[T(3,0)] = -(right + left) / (right - left);
+ out[T(3,1)] = -(top + bottom) / (top - bottom);
+ out[T(3,2)] = -(zfar + znear) / (zfar - znear);
+ out[T(3,3)] = 1.0f;
+
+ #undef T
+}
+
+static const char * vertex_shader =
+ "#version 130\n"
+ "in vec2 i_position;\n"
+ "in vec4 i_color;\n"
+ "out vec4 v_color;\n"
+ "uniform mat4 u_projection_matrix;\n"
+ "void main() {\n"
+ " v_color = i_color;\n"
+ " gl_Position = u_projection_matrix * vec4( i_position, 0.0, 1.0 );\n"
+ "}\n";
+
+static const char * fragment_shader =
+ "#version 130\n"
+ "in vec4 v_color;\n"
+ "out vec4 o_color;\n"
+ "void main() {\n"
+ " o_color = v_color;\n"
+ "}\n";
+
+typedef enum t_attrib_id
+{
+ attrib_position,
+ attrib_color
+} t_attrib_id;
+
+int main( int argc, char * argv[] )
+{
+ SDL_Init( SDL_INIT_VIDEO );
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+ SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
+ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
+ SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
+ SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
+ SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
+
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 );
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
+
+ static const int width = 800;
+ static const int height = 600;
+
+ SDL_Window * window = SDL_CreateWindow( "", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN );
+ SDL_GLContext context = SDL_GL_CreateContext( window );
+
+ GLuint vs, fs, program;
+
+ vs = glCreateShader( GL_VERTEX_SHADER );
+ fs = glCreateShader( GL_FRAGMENT_SHADER );
+
+ int length = strlen( vertex_shader );
+ glShaderSource( vs, 1, ( const GLchar ** )&vertex_shader, &length );
+ glCompileShader( vs );
+
+ GLint status;
+ glGetShaderiv( vs, GL_COMPILE_STATUS, &status );
+ if( status == GL_FALSE )
+ {
+ fprintf( stderr, "vertex shader compilation failed\n" );
+ return 1;
+ }
+
+ length = strlen( fragment_shader );
+ glShaderSource( fs, 1, ( const GLchar ** )&fragment_shader, &length );
+ glCompileShader( fs );
+
+ glGetShaderiv( fs, GL_COMPILE_STATUS, &status );
+ if( status == GL_FALSE )
+ {
+ fprintf( stderr, "fragment shader compilation failed\n" );
+ return 1;
+ }
+
+ program = glCreateProgram();
+ glAttachShader( program, vs );
+ glAttachShader( program, fs );
+
+ glBindAttribLocation( program, attrib_position, "i_position" );
+ glBindAttribLocation( program, attrib_color, "i_color" );
+ glLinkProgram( program );
+
+ glUseProgram( program );
+
+ glDisable( GL_DEPTH_TEST );
+ glClearColor( 0.5, 0.0, 0.0, 0.0 );
+ glViewport( 0, 0, width, height );
+
+ GLuint vao, vbo;
+
+ glGenVertexArrays( 1, &vao );
+ glGenBuffers( 1, &vbo );
+ glBindVertexArray( vao );
+ glBindBuffer( GL_ARRAY_BUFFER, vbo );
+
+ glEnableVertexAttribArray( attrib_position );
+ glEnableVertexAttribArray( attrib_color );
+
+ glVertexAttribPointer( attrib_color, 4, GL_FLOAT, GL_FALSE, sizeof( float ) * 6, 0 );
+ glVertexAttribPointer( attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof( float ) * 6, ( void * )(4 * sizeof(float)) );
+
+ const GLfloat g_vertex_buffer_data[] = {
+ /* R, G, B, A, X, Y */
+ 1, 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, width, 0,
+ 0, 0, 1, 1, width, height,
+
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 1, 1, width, height,
+ 1, 1, 1, 1, 0, height
+ };
+
+ glBufferData( GL_ARRAY_BUFFER, sizeof( g_vertex_buffer_data ), g_vertex_buffer_data, GL_STATIC_DRAW );
+
+ t_mat4x4 projection_matrix;
+ mat4x4_ortho( projection_matrix, 0.0f, (float)width, (float)height, 0.0f, 0.0f, 100.0f );
+ glUniformMatrix4fv( glGetUniformLocation( program, "u_projection_matrix" ), 1, GL_FALSE, projection_matrix );
+
+ for( ;; )
+ {
+ glClear( GL_COLOR_BUFFER_BIT );
+
+ SDL_Event event;
+ while( SDL_PollEvent( &event ) )
+ {
+ switch( event.type )
+ {
+ case SDL_KEYUP:
+ if( event.key.keysym.sym == SDLK_ESCAPE )
+ return 0;
+ break;
+ }
+ }
+
+ glBindVertexArray( vao );
+ glDrawArrays( GL_TRIANGLES, 0, 6 );
+
+ SDL_GL_SwapWindow( window );
+ SDL_Delay( 1 );
+ }
+
+ SDL_GL_DeleteContext( context );
+ SDL_DestroyWindow( window );
+ SDL_Quit();
+
+ return 0;
+}
+
diff --git a/res/eo1.bmp b/res/eo1.bmp
new file mode 100644
index 0000000..96a68d8
--- /dev/null
+++ b/res/eo1.bmp
Binary files differ
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..a73bf44
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,198 @@
+/*
+ * demoscene-eo, an ASCII art demoscene written as a gift for Emmanuel Otton retirement
+ * Copyright (C) 2019 Ludovic Pouzenc <ludovic@pouzenc.fr>
+ *
+ * This file is part of demoscene-eo.
+ *
+ * demoscene-eo 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 Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * demoscene-eo 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 demoscene-eo. If not, see <http://www.gnu.org/licenses/>
+ */
+#include "main.h"
+#include "scene00.h"
+#include "scene01.h"
+#include "scene02.h"
+#define SCENE_COUNT 3
+#define SCENE_NEXT do { scene = (scene+1)%SCENE_COUNT; } while(0)
+
+#define EXPR_MIN_SIZE ( ge.w<80 || ge.h<25 )
+#define TEXT_MIN_SIZE "80x25"
+
+int main(void)
+{
+ int done=0, lastscene=-1, scene=0, paused=0, res;
+ Uint32 sdl_win_flags = SDL_WINDOW_OPENGL;
+ graphical_env_t ge;
+ scene00_env_t s00e;
+ scene01_env_t s01e;
+ scene02_env_t s02e;
+
+ caca_event_t caca_ev;
+ SDL_RendererInfo renderer_info;
+ SDL_Event sdl_ev;
+
+ // Initialize libcaca (http://caca.zoy.org/doxygen/libcaca/caca_8h.html)
+ ge.dp = caca_create_display(NULL);
+ if(!ge.dp) return 1;
+ caca_set_display_title(ge.dp, "demoscene-eo");
+ caca_set_display_time(ge.dp, 16666); // 1e6µs/60 = 16666.66... It is ~60 fps
+ ge.cv = caca_get_canvas(ge.dp);
+
+ ge.d = caca_create_dither(32, 256, 256, 256*4, 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
+ if ( !ge.d ) return 2;
+ caca_set_dither_color(ge.d, "16");
+
+ // Initialize SDL (http://wiki.libsdl.org/SDL_CreateWindowAndRenderer)
+ // Useful snippet : https://gist.github.com/koute/7391344
+ res = SDL_Init(SDL_INIT_VIDEO);
+ if ( res == -1) return 3;
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+ SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
+ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
+ SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
+ SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
+ SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 );
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
+
+ //XXX for final version, consider sdl_win_flags |= SDL_WINDOW_HIDDEN;
+ res = SDL_CreateWindowAndRenderer(256, 256, sdl_win_flags, &ge.sdl_win, &ge.sdl_rndr);
+ if ( res == -1) return 4;
+ SDL_SetWindowTitle(ge.sdl_win, "SDL/GL debug");
+ res = SDL_GetRendererInfo(ge.sdl_rndr, &renderer_info);
+ if ( res < 0 ) return 5;
+ if ( !(renderer_info.flags & SDL_RENDERER_ACCELERATED)) return 6;
+ if ( !(renderer_info.flags & SDL_RENDERER_TARGETTEXTURE)) return 7;
+ ge.sdl_target = SDL_CreateTexture(ge.sdl_rndr, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 256, 256);
+ if ( ge.sdl_target == NULL ) return 9;
+ ge.raw_target = malloc(256*256*4);
+ if ( ge.raw_target == NULL ) return 10;
+ ge.gl_ctx = SDL_GL_CreateContext(ge.sdl_win);
+ if ( ge.gl_ctx == NULL ) return 11;
+
+
+ // Initialize OpenGL
+ glShadeModel(GL_SMOOTH);
+ glClearDepth(1.0f);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+ glDisable(GL_TEXTURE_2D);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_FRONT);
+ glViewport(0, 0, (GLsizei)256, (GLsizei)256);
+ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, 1.0f, 0.1f, 100.0f); // 1.0f==ratio
+ glMatrixMode(GL_MODELVIEW); glLoadIdentity();
+
+ // Main libcaca loop for caca window (OpenGL could be used in sceneN_next())
+ ge.framecount=0;
+ do {
+ // Check canvas size at every frame because of unreliable CACA_EVENT_RESIZE
+ ge.w = caca_get_canvas_width(ge.cv);
+ ge.h = caca_get_canvas_height(ge.cv);
+ if ( EXPR_MIN_SIZE ) {
+ caca_set_color_ansi(ge.cv, CACA_BLACK, CACA_WHITE);
+ caca_put_str(ge.cv, 0, 0, "Need a minimum of " TEXT_MIN_SIZE " terminal");
+ } else if (!paused) {
+ // init / free if scene transition
+ if ( lastscene != scene ) {
+ switch(lastscene) {
+ case 0: scene00_free(&ge, &s00e); break;
+ case 1: scene01_free(&ge, &s01e); break;
+ case 2: scene02_free(&ge, &s02e); break;
+ }
+ }
+ while ( lastscene != scene ) {
+ ge.sdl_ticks = SDL_GetTicks();
+ ge.sc_framecount = 0;
+ switch(scene) {
+ case 0: res = scene00_init(&ge, &s00e); break;
+ case 1: res = scene01_init(&ge, &s01e); break;
+ case 2: res = scene02_init(&ge, &s02e); break;
+ }
+ // If scene init fail, skip to the next one
+ if (res) SCENE_NEXT; else lastscene = scene;
+ }
+ // Compute current scene0 frame
+ ge.sdl_ticks = SDL_GetTicks(); // This value wraps if the program runs for more than ~49 days
+ switch(scene) {
+ case 0: res = scene00_next(&ge, &s00e); break;
+ case 1: res = scene01_next(&ge, &s01e); break;
+ case 2: res = scene02_next(&ge, &s02e); break;
+ }
+ if (res) SCENE_NEXT;
+ ge.framecount++;
+ ge.sc_framecount++;
+ }
+ // Display it
+ caca_refresh_display(ge.dp); // Auto framerate limiting (see caca_set_display_time())
+
+ // Event handling for the libcaca "window" (depending on CACA_DRIVER env variable)
+ if ( caca_get_event(ge.dp, CACA_EVENT_KEY_PRESS|CACA_EVENT_RESIZE|CACA_EVENT_QUIT, &caca_ev, 0) ) {
+ switch(caca_get_event_type(&caca_ev)) {
+ case CACA_EVENT_QUIT:
+ done = 1;
+ break;
+ case CACA_EVENT_KEY_PRESS:
+ switch(caca_get_event_key_ch(&caca_ev)) {
+ case 'q': done = 1; break;
+ case 'p': paused = !paused; break;
+ case CACA_KEY_ESCAPE: SCENE_NEXT; break;
+ }
+ break;
+ /* On Debian 10, no CACA_EVENT_RESIZE when using x11 CACA_DRIVER
+ case CACA_EVENT_RESIZE:
+ w = caca_get_event_resize_width(&caca_ev);
+ h = caca_get_event_resize_height(&caca_ev);
+ small = EXPR_MIN_SIZE;
+ break;
+ */
+ default:
+ break;
+ }
+ }
+ // Event handling for the SDL/GL window (debug purposes)
+ while(SDL_PollEvent(&sdl_ev)) {
+ switch(sdl_ev.type) {
+ case SDL_QUIT:
+ done = 1;
+ break;
+ case SDL_KEYDOWN:
+ switch(sdl_ev.key.keysym.sym) {
+ case SDLK_q: done = 1; break;
+ case SDLK_p: paused = !paused; break;
+ case SDLK_ESCAPE: SCENE_NEXT; break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ } while(!done);
+
+ caca_free_dither(ge.d);
+ caca_free_display(ge.dp);
+ ge.cv=NULL;
+ SDL_GL_DeleteContext(ge.gl_ctx);
+ SDL_DestroyTexture(ge.sdl_target);
+ SDL_DestroyRenderer(ge.sdl_rndr);
+ SDL_DestroyWindow(ge.sdl_win);
+ SDL_Quit();
+ return 0;
+}
diff --git a/src/main.h b/src/main.h
new file mode 100644
index 0000000..b2b0a6e
--- /dev/null
+++ b/src/main.h
@@ -0,0 +1,23 @@
+#ifndef MAIN_H_INCLUDED
+#define MAIN_H_INCLUDED
+
+#include <caca.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.h>
+#include <GL/glu.h>
+
+typedef struct {
+ caca_display_t *dp;
+ caca_canvas_t *cv;
+ caca_dither_t *d;
+ int w, h; // caca terminal size in characters
+ SDL_Window* sdl_win;
+ SDL_Renderer *sdl_rndr;
+ SDL_Texture *sdl_target;
+ void *raw_target;
+ SDL_GLContext gl_ctx;
+ Uint32 sdl_ticks;
+ Uint32 framecount;
+ Uint32 sc_framecount;
+} graphical_env_t;
+#endif
diff --git a/src/scene00.c b/src/scene00.c
new file mode 100644
index 0000000..746db29
--- /dev/null
+++ b/src/scene00.c
@@ -0,0 +1,73 @@
+/*
+ * demoscene-eo, an ASCII art demoscene written as a gift for Emmanuel Otton retirement
+ * Copyright (C) 2019 XXXXXX XXXXXXX <xxxxxx@xxxxxx.fr>
+ *
+ * This file is part of demoscene-eo.
+ *
+ * demoscene-eo 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 Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * demoscene-eo 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 demoscene-eo. If not, see <http://www.gnu.org/licenses/>
+ */
+#include "scene00.h"
+
+int scene00_init(graphical_env_t *ge, scene00_env_t *se) {
+ SDL_Surface *bmpSurf = SDL_LoadBMP("./res/eo1.bmp");
+ se->eo1 = SDL_CreateTextureFromSurface(ge->sdl_rndr, bmpSurf);
+ SDL_FreeSurface(bmpSurf);
+
+ return 0;
+}
+
+void scene00_free(graphical_env_t *ge, scene00_env_t *se) {
+ SDL_DestroyTexture(se->eo1); se->eo1=NULL;
+}
+
+int scene00_next(graphical_env_t *ge, scene00_env_t *se) {
+ // Shorthands
+ caca_canvas_t *cv = ge->cv;
+ int w = ge->w, h = ge->h;
+ Uint32 frame = ge->sc_framecount;
+ SDL_Renderer *r = ge->sdl_rndr;
+ // Local vars
+ int res;
+
+ // https://gist.github.com/Twinklebear/8265888
+ // https://forums.libsdl.org/viewtopic.php?p=51634
+
+ // Render all the stuff on target texture
+ SDL_SetRenderTarget(r, ge->sdl_target);
+ SDL_RenderCopy(r, se->eo1, NULL, NULL);
+ // [...]
+
+ // Copy the SDL screen to SDL debug window (and display it, not mandatory)
+ SDL_SetRenderTarget(r, NULL);
+ SDL_RenderCopy(r, ge->sdl_target, NULL, NULL);
+ SDL_RenderPresent(r);
+
+ // Download the rendered texture from videocard to main memory
+ res = SDL_RenderReadPixels(r, NULL, 0, ge->raw_target, 256*4);
+
+ // "convert" the raw pixel stream to ASCII art on caca canevas
+ if ( res == 0 ) caca_dither_bitmap(cv, 0, 0, w, h, ge->d, ge->raw_target);
+
+ // Add things on top of caca canvas
+ caca_set_color_ansi(cv, CACA_BLACK, CACA_WHITE);
+ caca_put_str(cv, (w-17)/2, h/2, "This is a message");
+ caca_draw_line(cv,6,6,w-14,11, '*');
+ caca_draw_thin_line(cv,frame%10,frame%10,w-10+frame%10,h-10+frame%10);
+
+ if ( frame >= 100 ) {
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/scene00.h b/src/scene00.h
new file mode 100644
index 0000000..b1c9d9d
--- /dev/null
+++ b/src/scene00.h
@@ -0,0 +1,12 @@
+#ifndef SCENE00_H_INCLUDED
+#define SCENE00_H_INCLUDED
+
+#include "main.h"
+typedef struct {
+ SDL_Texture *eo1;
+} scene00_env_t;
+
+int scene00_init(graphical_env_t *ge, scene00_env_t *se);
+void scene00_free(graphical_env_t *ge, scene00_env_t *se);
+int scene00_next(graphical_env_t *ge, scene00_env_t *se);
+#endif
diff --git a/src/scene01.c b/src/scene01.c
new file mode 100644
index 0000000..2b3e9f5
--- /dev/null
+++ b/src/scene01.c
@@ -0,0 +1,49 @@
+/*
+ * demoscene-eo, an ASCII art demoscene written as a gift for Emmanuel Otton retirement
+ * Copyright (C) 2019 XXXXXX XXXXXXX <xxxxxx@xxxxxx.fr>
+ *
+ * This file is part of demoscene-eo.
+ *
+ * demoscene-eo 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 Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * demoscene-eo 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 demoscene-eo. If not, see <http://www.gnu.org/licenses/>
+ */
+#include "scene01.h"
+
+int scene01_init(graphical_env_t *ge, scene01_env_t *se) {
+ return 0;
+}
+
+void scene01_free(graphical_env_t *ge, scene01_env_t *se) {
+}
+
+int scene01_next(graphical_env_t *ge, scene01_env_t *se) {
+ // Shorthands
+ caca_canvas_t *cv = ge->cv;
+ int w = ge->w, h = ge->h;
+ Uint32 frame = ge->sc_framecount;
+
+ //XXX remove me
+ ((Uint32 *)ge->raw_target)[frame%(256*256)]=frame<<((frame%3)*8);
+
+ caca_clear_canvas(cv);
+ caca_set_dither_gamma(ge->d, (100-frame%100)/100.0);
+ caca_dither_bitmap(cv, 0, 0, w, h, ge->d, ge->raw_target);
+
+ caca_set_color_ansi(cv, CACA_WHITE, CACA_BLACK);
+ caca_put_str(cv, (w-17)/2, h/2, "This is a message");
+
+ if ( frame >= 300 ) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/scene01.h b/src/scene01.h
new file mode 100644
index 0000000..1f22de7
--- /dev/null
+++ b/src/scene01.h
@@ -0,0 +1,12 @@
+#ifndef SCENE01_H_INCLUDED
+#define SCENE01_H_INCLUDED
+
+#include "main.h"
+typedef struct {
+
+} scene01_env_t;
+
+int scene01_init(graphical_env_t *ge, scene01_env_t *se);
+void scene01_free(graphical_env_t *ge, scene01_env_t *se);
+int scene01_next(graphical_env_t *ge, scene01_env_t *se);
+#endif
diff --git a/src/scene02.c b/src/scene02.c
new file mode 100644
index 0000000..1989bf0
--- /dev/null
+++ b/src/scene02.c
@@ -0,0 +1,42 @@
+/*
+ * demoscene-eo, an ASCII art demoscene written as a gift for Emmanuel Otton retirement
+ * Copyright (C) 2019 XXXXXX XXXXXXX <xxxxxx@xxxxxx.fr>
+ *
+ * This file is part of demoscene-eo.
+ *
+ * demoscene-eo 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 Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * demoscene-eo 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 demoscene-eo. If not, see <http://www.gnu.org/licenses/>
+ */
+#include "scene02.h"
+
+int scene02_init(graphical_env_t *ge, scene02_env_t *se) {
+ return 0;
+}
+
+void scene02_free(graphical_env_t *ge, scene02_env_t *se) {
+}
+
+int scene02_next(graphical_env_t *ge, scene02_env_t *se) {
+ // Shorthands
+ caca_canvas_t *cv = ge->cv;
+ //int w = ge->w, h = ge->h;
+ Uint32 frame = ge->sc_framecount;
+
+ caca_clear_canvas(cv);
+
+ if ( frame >= 100 ) {
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/scene02.h b/src/scene02.h
new file mode 100644
index 0000000..49abbfb
--- /dev/null
+++ b/src/scene02.h
@@ -0,0 +1,12 @@
+#ifndef SCENE02_H_INCLUDED
+#define SCENE02_H_INCLUDED
+
+#include "main.h"
+typedef struct {
+
+} scene02_env_t;
+
+int scene02_init(graphical_env_t *ge, scene02_env_t *se);
+void scene02_free(graphical_env_t *ge, scene02_env_t *se);
+int scene02_next(graphical_env_t *ge, scene02_env_t *se);
+#endif