/* * demoscene-eo, an ASCII art demoscene written as a gift for Emmanuel Otton retirement * Copyright (C) 2019 Ludovic Pouzenc * * 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 */ #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; }