summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Pouzenc <ludovic@pouzenc.fr>2019-09-01 21:54:50 +0200
committerLudovic Pouzenc <ludovic@pouzenc.fr>2019-09-01 21:54:50 +0200
commit235cbc46a64ac63fd53df8a39a8681a8fcea2848 (patch)
tree3d792f5e4a1bb7f8054948b74b389be1a128b342
downloaddemoscene-eo-235cbc46a64ac63fd53df8a39a8681a8fcea2848.tar.gz
demoscene-eo-235cbc46a64ac63fd53df8a39a8681a8fcea2848.tar.bz2
demoscene-eo-235cbc46a64ac63fd53df8a39a8681a8fcea2848.zip
Initial import. First working main loop.
Switching from scene to scene is done. Loading image to SDL, download SDL texture from VRAM to RAM is done. caca background from SDL texture is "done". GL drawing is not yet tried. Considering OpenGL3 + shaders.
-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