summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c362
1 files changed, 266 insertions, 96 deletions
diff --git a/src/main.c b/src/main.c
index 3f18052..94d6195 100644
--- a/src/main.c
+++ b/src/main.c
@@ -18,127 +18,178 @@
* along with demoscene-eo. If not, see <http://www.gnu.org/licenses/>
*/
#include "main.h"
-#include "scene00.h"
-#include "scene01.h"
-#include "scene02.h"
+
+#include <stdlib.h> // calloc()
+#include <strings.h> // bzero()
+#include <sys/mman.h> // mmap()
+#include <semaphore.h> // sem_t, sem_init(), Link with -pthread
+#include <unistd.h> // fork()
+#include <sys/wait.h> // wait()
+#include <errno.h> // errno
+#include <stdint.h> // uint32_t
+#include <stdio.h> // printf()
+
+#define TRACE(hint) printf("%s(): %s\n", __func__, hint)
#define SCENE_COUNT 3
-#define SCENE_NEXT do { scene = (scene+1)%SCENE_COUNT; } while(0)
+#define SCENE_NEXT do { shm->scene = (shm->scene+1)%SCENE_COUNT; } while(0)
-#define EXPR_MIN_SIZE ( ge.w<80 || ge.h<25 )
+#define EXPR_MIN_SIZE ( shm->ge.w<80 || shm->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;
+#define SEM_POST(sem,errcode) \
+ do { \
+ printf("%s(): sem_post(%s,%i) call\n", __func__, #sem, errcode);\
+ if ( sem_post(sem) == -1 ) { return errcode; } \
+ printf("%s(): sem_post(%s,%i) done\n", __func__, #sem, errcode);\
+ } while(0)
+
+#define SEM_WAIT(sem,errcode) \
+ do { \
+ printf("%s(): sem_wait(%s,%i) call\n", __func__, #sem, errcode);\
+ while ( sem_wait(&shm->parent_can_read_result) == -1 ) { \
+ switch(errno) { \
+ case EINTR: \
+ case EAGAIN: \
+ break; \
+ default: \
+ return errcode; \
+ } \
+ } \
+ printf("%s(): sem_wait(%s,%i) done\n", __func__, #sem, errcode);\
+ } while(0)
+
+typedef struct {
+ sem_t worker_gl_can_render, worker_sdl_can_render, parent_can_read_result;
+ int scene, paused, done;
graphical_env_t ge;
scene00_env_t s00e;
scene01_env_t s01e;
scene02_env_t s02e;
+} shm_t;
- caca_event_t caca_ev;
- SDL_RendererInfo renderer_info;
- SDL_Event sdl_ev;
+int do_fork1();
+int do_fork2();
+int parent();
+int worker_sdl();
+int worker_gl();
- // 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);
+shm_t *shm;
- 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");
+int main() {
+ TRACE("call");
+ shm = mmap(NULL, sizeof(shm_t), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
+ if ( shm == NULL ) return 1;
+ bzero(shm, sizeof(shm_t));
- // 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 );
+ if (sem_init(&shm->worker_gl_can_render, 1, 0) < 0) return 2;
+ if (sem_init(&shm->worker_sdl_can_render, 1, 0) < 0) return 3;
+ if (sem_init(&shm->parent_can_read_result, 1, 0) < 0) return 4;
- //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;
+ shm->ge.raw_target = calloc(FBUF_W*FBUF_H, sizeof(uint32_t));
+ if ( shm->ge.raw_target == NULL ) return 5;
- // Initialize OpenGL
- ge.gl_ctx = SDL_GL_CreateContext(ge.sdl_win);
- if ( ge.gl_ctx == NULL ) return 11;
+ return do_fork1();
+}
- // Main libcaca loop for caca window (OpenGL could be used in sceneN_next())
- ge.framecount=0;
+int do_fork1() {
+ TRACE("call");
+ switch (fork()) {
+ case -1: return 4; break;
+ case 0: return worker_sdl(); break;
+ default: return do_fork2(); break;
+ }
+}
+
+int do_fork2() {
+ TRACE("call");
+ switch (fork()) {
+ case -1: return 5; break;
+ case 0: return worker_gl(); break;
+ default: return parent(); break;
+ }
+}
+
+int parent() {
+ int lastscene=-1, res, child_status;
+ caca_event_t caca_ev;
+
+ TRACE("call");
+
+ // Initialize libcaca (http://caca.zoy.org/doxygen/libcaca/caca_8h.html)
+ shm->ge.dp = caca_create_display(NULL);
+ if(!shm->ge.dp) return 1;
+ caca_set_display_title(shm->ge.dp, "demoscene-eo");
+ caca_set_display_time(shm->ge.dp, 16666); // 1e6µs/60 = 16666.66... It is ~60 fps
+ shm->ge.cv = caca_get_canvas(shm->ge.dp);
+
+ shm->ge.d = caca_create_dither(32, FBUF_W, FBUF_H, FBUF_W*4, 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
+ if ( !shm->ge.d ) return 2;
+ caca_set_dither_color(shm->ge.d, "16");
+
+ // Main libcaca loop for caca window
+ shm->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);
+ shm->ge.w = caca_get_canvas_width(shm->ge.cv);
+ shm->ge.h = caca_get_canvas_height(shm->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) {
+ caca_set_color_ansi(shm->ge.cv, CACA_BLACK, CACA_WHITE);
+ caca_put_str(shm->ge.cv, 0, 0, "Need a minimum of " TEXT_MIN_SIZE " terminal");
+ } else if (!shm->paused) {
// init / free if scene transition
- if ( lastscene != scene ) {
+ if ( lastscene != shm->scene ) {
switch(lastscene) {
- case 0: scene00_free(&ge, &s00e); break;
- case 1: scene01_free(&ge, &s01e); break;
- case 2: scene02_free(&ge, &s02e); break;
+ case 0: scene00_free(&shm->ge, &shm->s00e); break;
+ case 1: scene01_free(&shm->ge, &shm->s01e); break;
+ case 2: scene02_free(&shm->ge, &shm->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;
+ while ( lastscene != shm->scene ) {
+ shm->ge.sdl_ticks = SDL_GetTicks();
+ shm->ge.sc_framecount = 0;
+ switch(shm->scene) {
+ case 0: res = scene00_init(&shm->ge, &shm->s00e); break;
+ case 1: res = scene01_init(&shm->ge, &shm->s01e); break;
+ case 2: res = scene02_init(&shm->ge, &shm->s02e); break;
}
// If scene init fail, skip to the next one
- if (res) SCENE_NEXT; else lastscene = scene;
+ if (res) SCENE_NEXT; else lastscene = shm->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;
+ shm->ge.sdl_ticks = SDL_GetTicks(); // This value wraps if the program runs for more than ~49 days
+
+ SEM_POST(&shm->worker_gl_can_render,30);
+ SEM_WAIT(&shm->parent_can_read_result,31);
+
+ SEM_POST(&shm->worker_sdl_can_render,32);
+ SEM_WAIT(&shm->parent_can_read_result,33);
+
+ // Compute current scene frame (caca part)
+ switch(shm->scene) {
+ case 0: res = scene00_next_caca(&shm->ge, &shm->s00e); break;
+ case 1: res = scene01_next_caca(&shm->ge, &shm->s01e); break;
+ case 2: res = scene02_next_caca(&shm->ge, &shm->s02e); break;
}
if (res) SCENE_NEXT;
- ge.framecount++;
- ge.sc_framecount++;
+ shm->ge.framecount++;
+ shm->ge.sc_framecount++;
}
// Display it
- caca_refresh_display(ge.dp); // Auto framerate limiting (see caca_set_display_time())
+ caca_refresh_display(shm->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) ) {
+ if ( caca_get_event(shm->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;
+ shm->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 'q': shm->done = 1; break;
+ case 'p': shm->paused = !shm->paused; break;
case CACA_KEY_ESCAPE: SCENE_NEXT; break;
}
break;
- /* On Debian 10, no CACA_EVENT_RESIZE when using x11 CACA_DRIVER
+ /* On Debian 10, no CACA_EVENT_RESIZE fired 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);
@@ -149,16 +200,68 @@ int main(void)
break;
}
}
- // Event handling for the SDL/GL window (debug purposes)
+ } while(!shm->done);
+
+ caca_free_dither(shm->ge.d);
+ caca_free_display(shm->ge.dp);
+ shm->ge.cv=NULL;
+
+ // reap forked processes (order doesn't matter)
+ if ( wait(&child_status) != -1 ) {
+ if ( child_status > 0 ) return child_status;
+ }
+ if ( wait(&child_status) != -1 ) {
+ if ( child_status > 0 ) return child_status;
+ }
+ return 0;
+}
+
+int worker_sdl() {
+ int res;
+ Uint32 sdl_win_flags = 0; //XXX for final version, consider sdl_win_flags = SDL_WINDOW_HIDDEN;
+ SDL_RendererInfo renderer_info;
+ SDL_Event sdl_ev;
+
+ TRACE("call");
+
+ // 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;
+ atexit(SDL_Quit);
+
+ res = SDL_CreateWindowAndRenderer(FBUF_W, FBUF_H, sdl_win_flags, &shm->ge.sdl_win, &shm->ge.sdl_rndr);
+ if ( res == -1) return 4;
+ SDL_SetWindowTitle(shm->ge.sdl_win, "SDL debug");
+ res = SDL_GetRendererInfo(shm->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;
+ shm->ge.sdl_target = SDL_CreateTexture(shm->ge.sdl_rndr, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, FBUF_W, FBUF_H);
+ if ( shm->ge.sdl_target == NULL ) return 9;
+
+ while ( !shm->done ) {
+ //FIXME change for TRYWAIT for event handling (+delay)
+ SEM_WAIT(&shm->worker_sdl_can_render,20);
+
+ // Compute current scene frame (sdl part)
+ switch(shm->scene) {
+ case 0: res = scene00_next_sdl(&shm->ge, &shm->s00e); break;
+ case 1: res = scene01_next_sdl(&shm->ge, &shm->s01e); break;
+ case 2: res = scene02_next_sdl(&shm->ge, &shm->s02e); break;
+ }
+ if (res) SCENE_NEXT;
+
+ // Event handling for the SDL window (debug purposes)
while(SDL_PollEvent(&sdl_ev)) {
switch(sdl_ev.type) {
case SDL_QUIT:
- done = 1;
+ shm->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_q: shm->done = 1; break;
+ case SDLK_p: shm->paused = !shm->paused; break;
case SDLK_ESCAPE: SCENE_NEXT; break;
}
break;
@@ -166,15 +269,82 @@ int main(void)
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();
+
+ SEM_POST(&shm->parent_can_read_result, 21);
+ }
+
+ SDL_DestroyRenderer(shm->ge.sdl_rndr);
+ SDL_DestroyTexture(shm->ge.sdl_target);
+ SDL_DestroyWindow(shm->ge.sdl_win);
+
+ return 0;
+}
+
+int worker_gl() {
+ int res;
+ //Uint32 sdl_win_flags = SDL_WINDOW_OPENGL;
+ SDL_Event gl_ev;
+
+ TRACE("call");
+
+ // 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;
+ atexit(SDL_Quit);
+
+ 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 );
+
+ // Initialize OpenGL
+ shm->ge.gl_win = SDL_CreateWindow("GL Debug", 0, SDL_WINDOWPOS_CENTERED, FBUF_W, FBUF_H, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN );
+ shm->ge.gl_ctx = SDL_GL_CreateContext(shm->ge.gl_win);
+ if ( shm->ge.gl_ctx == NULL ) return 11;
+
+ while ( !shm->done ) {
+ //FIXME change for TRYWAIT for event handling (+delay)
+ SEM_WAIT(&shm->worker_gl_can_render,10);
+
+ // Compute current scene frame (gl part)
+ switch(shm->scene) {
+ case 0: res = scene00_next_gl(&shm->ge, &shm->s00e); break;
+ case 1: res = scene01_next_gl(&shm->ge, &shm->s01e); break;
+ case 2: res = scene02_next_gl(&shm->ge, &shm->s02e); break;
+ }
+ if (res) SCENE_NEXT;
+
+
+ // Event handling for the GL window (debug purposes)
+ while(SDL_PollEvent(&gl_ev)) {
+ switch(gl_ev.type) {
+ case SDL_QUIT:
+ shm->done = 1;
+ break;
+ case SDL_KEYDOWN:
+ switch(gl_ev.key.keysym.sym) {
+ case SDLK_q: shm->done = 1; break;
+ case SDLK_p: shm->paused = !shm->paused; break;
+ case SDLK_ESCAPE: SCENE_NEXT; break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ SEM_POST(&shm->parent_can_read_result, 11);
+ }
+
+ //SDL_DestroyTexture(shm->ge.gl_target);
+ SDL_GL_DeleteContext(shm->ge.gl_ctx);
+ SDL_DestroyWindow(shm->ge.gl_win);
+
return 0;
}