--- /dev/null
+on_speed = 2/100.0
+off_speed = 2/25.0
+flatness = 0.000001
+start_dwell = 4
+curve_dwell = 0
+corner_dwell = 5
+end_dwell = 4
+switch_dwell = 6
+closed_overdraw = 3
+closed_start_dwell = 3
+closed_end_dwell = 3
+extra_first_dwell = 0
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48+devel r"
+ width="215"
+ height="155"
+ sodipodi:docname="27c3-logo.svg">
+ <metadata
+ id="metadata8">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1912"
+ inkscape:window-height="1005"
+ id="namedview4"
+ showgrid="true"
+ inkscape:snap-global="true"
+ inkscape:zoom="2.9126781"
+ inkscape:cx="146.35732"
+ inkscape:cy="96.241399"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3071"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <path
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 110,75 -50,0 0,-45 25,0 0,-5 -25,0 0,-20 45,0 0,25 30,0 0,-5 -25,0 0,-20 45,0 0,70 -20,0 0,-25 -55,0 0,5 50,0 0,25 25,0 0,70 -95,0 0,-70 45,0 0,45 -20,0 0,-25 -5,0 0,30 55,0 0,-5 -25,0 0,-20 25,0 0,-5 -25,0 z"
+ id="path3158"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "libol.h"
+#include "ilda.h"
+#include "text.h"
+#include <math.h>
+#include <stdio.h>
+
+/* cubes demo */
+
+void cubes_init(void **ctx, void *arg, OLRenderParams *params)
+{
+}
+
+void cubes_deinit(void *ctx)
+{
+}
+
+void cubes_render(void *ctx, float time)
+{
+ int i;
+
+ olLoadIdentity3();
+ olLoadIdentity();
+ olPerspective(60, 1, 1, 100);
+ olTranslate3(0, 0, -3);
+
+ for(i=0; i<2; i++) {
+ olScale3(0.6, 0.6, 0.6);
+
+ olRotate3Z(time * M_PI * 0.1);
+ olRotate3Y(time * M_PI * 0.8);
+ olRotate3X(time * M_PI * 0.73);
+
+ olBegin(OL_LINESTRIP);
+ olVertex3(-1, -1, -1, C_WHITE);
+ olVertex3( 1, -1, -1, C_WHITE);
+ olVertex3( 1, 1, -1, C_WHITE);
+ olVertex3(-1, 1, -1, C_WHITE);
+ olVertex3(-1, -1, -1, C_WHITE);
+ olVertex3(-1, -1, 1, C_WHITE);
+ olEnd();
+
+ olBegin(OL_LINESTRIP);
+ olVertex3( 1, 1, 1, C_WHITE);
+ olVertex3(-1, 1, 1, C_WHITE);
+ olVertex3(-1, -1, 1, C_WHITE);
+ olVertex3( 1, -1, 1, C_WHITE);
+ olVertex3( 1, 1, 1, C_WHITE);
+ olVertex3( 1, 1, -1, C_WHITE);
+ olEnd();
+
+ olBegin(OL_LINESTRIP);
+ olVertex3( 1, -1, -1, C_WHITE);
+ olVertex3( 1, -1, 1, C_WHITE);
+ olEnd();
+
+ olBegin(OL_LINESTRIP);
+ olVertex3(-1, 1, 1, C_WHITE);
+ olVertex3(-1, 1, -1, C_WHITE);
+ olEnd();
+ }
+}
+
+/* laser scanner diagram thing */
+/* yes this is ugly stuff */
+
+static int points_left = 0;
+static int point_step = 1;
+static int delay = 0;
+static int delay_ctr = 0;
+static int include_dark_points = 0;
+
+static void cutoff(float *x, float *y, uint32_t *color)
+{
+ static float save_x, save_y;
+ static uint32_t save_color;
+ static int points_dot = 0;
+ if ((!include_dark_points) && (*color == C_BLACK)) {
+ if (points_left)
+ return;
+ *x = save_x;
+ *y = save_y;
+ }
+ if ((points_left-delay) > 0) {
+ points_left -= point_step;
+ save_x = *x;
+ save_y = *y;
+ save_color = *color;
+ points_dot = 200;
+ } else {
+ if (points_left > delay_ctr && points_left < delay && (delay - points_left) > 20)
+ points_dot = 0;
+ *x = save_x;
+ *y = save_y;
+ if (points_dot) {
+ *color = C_WHITE;
+ points_dot--;
+ } else {
+ *color = C_BLACK;
+ }
+ }
+ if (delay > delay_ctr)
+ delay_ctr += point_step;
+}
+
+void diag_init(void **ctx, void *arg, OLRenderParams *params)
+{
+ *ctx = olLoadIlda("27c3-logo.ild");
+ if (!*ctx)
+ olLog("Failed to load 27c3-logo.ild\n");
+
+ params->off_speed = 2.0/25.0;
+ params->start_wait = 15;
+}
+
+void diag_deinit(void *ctx)
+{
+ if (ctx)
+ olFreeIlda(ctx);
+}
+
+static void draw_galvo(void)
+{
+ point_step = 10;
+
+ olBegin(OL_LINESTRIP);
+ olVertex3(-5, -10, -5, C_WHITE);
+ olVertex3(-5, 10, -5, C_WHITE);
+ olVertex3(5, 10, 5, C_WHITE);
+ olVertex3(5, -10, 5, C_WHITE);
+ olVertex3(-5, -10, -5, C_WHITE);
+ olEnd();
+
+ olBegin(OL_LINESTRIP);
+ olVertex3(2, -10, 2, C_WHITE);
+ olVertex3(2, -20, 0, C_WHITE);
+ olEnd();
+ olBegin(OL_LINESTRIP);
+ olVertex3(-2, -10, -2, C_WHITE);
+ olVertex3(-2, -20, 0, C_WHITE);
+ olEnd();
+ olBegin(OL_LINESTRIP);
+ olVertex3(-9, -50, 0, C_WHITE);
+ olVertex3(-9, -20, 0, C_WHITE);
+ olVertex3(9, -20, 0, C_WHITE);
+ olVertex3(9, -50, 0, C_WHITE);
+ olEnd();
+ olBegin(OL_LINESTRIP);
+ olVertex3(-20, -50, 0, C_WHITE);
+ olVertex3(-20, -70, 0, C_WHITE);
+ olVertex3(20, -70, 0, C_WHITE);
+ olVertex3(20, -50, 0, C_WHITE);
+ olVertex3(-20, -50, 0, C_WHITE);
+ olEnd();
+
+ point_step = 4;
+ olDrawString(olGetDefaultFont(), -15, -55, 14, C_WHITE, "Galvo");
+
+}
+
+typedef struct {
+ float time;
+ float x, y, z;
+ float rx, ry, rz;
+} campt;
+
+static campt campoints[] = {
+ {0, -140, 0, -120, 0, 0, 0},
+ {3.0, -140, 0, -120, 0, 0, 0},
+ {4.5, -100, 0, 0, 0, 0, 0},
+ {6.5, 10, -20, -70, 0, 0, 0},
+ {13, 10, -20, -70, 0, 0, 0},
+ {16, 50, 50, 10, -M_PI/2, 0, -0.5},
+ {17, 0, 140, 0, -M_PI/2, 0, 0},
+ {18, 0, 310, 0, -M_PI/2, 0, 0},
+};
+
+#define LOGO_START 14
+#define FADE_START 16
+#define FADE_END 17
+
+#define NUM_CAMPOINTS (sizeof(campoints)/sizeof(campoints[0]))
+
+void diag_render(void *ctx, float time)
+{
+ int i;
+
+ delay = 0;
+ delay_ctr = 0;
+
+ //time += 10;
+
+ //time -= 1;
+ if (time < 0)
+ time = 0;
+
+ int spl = time * 1000;
+ points_left = spl;
+
+ int maincolor = 255;
+ if (time > FADE_START)
+ maincolor = (FADE_END - time) * 255;
+
+ olSetPixelShader(NULL);
+ olLoadIdentity3();
+ olLoadIdentity();
+
+ point_step = 10;
+
+ olFrustum(-1, 1, -1, 1, 3, 100);
+ olTranslate3(0, 0, -3);
+ olScale3(0.01, 0.01, 0.01);
+
+ campt *p = &campoints[0];
+
+ for (i=0; i<NUM_CAMPOINTS; i++) {
+ if (campoints[i].time > time)
+ break;
+ p = &campoints[i];
+ }
+
+ campt dest;
+
+ dest = *p;
+
+ if (i == NUM_CAMPOINTS) {
+ dest = *p;
+ } else {
+ float subpos = (time - p[0].time) / (p[1].time - p[0].time);
+ subpos = (sinf((subpos - 0.5) * M_PI) + 1)/2;
+ olLog("Subpos: %f\n", subpos);
+ dest.x = p[0].x * (1-subpos) + p[1].x * subpos;
+ dest.y = p[0].y * (1-subpos) + p[1].y * subpos;
+ dest.z = p[0].z * (1-subpos) + p[1].z * subpos;
+ dest.rx = p[0].rx * (1-subpos) + p[1].rx * subpos;
+ dest.ry = p[0].ry * (1-subpos) + p[1].ry * subpos;
+ dest.rz = p[0].rz * (1-subpos) + p[1].rz * subpos;
+ }
+
+ olLog("Camera @ %f: %f %f %f %f %f %f\n", time, dest.x, dest.y, dest.z, dest.rx, dest.ry, dest.rz);
+
+ olRotate3X(dest.rx);
+ olRotate3Y(dest.ry);
+ olRotate3Z(dest.rz);
+ olTranslate3(-dest.x, -dest.y, -dest.z);
+
+ int logo_points = (time - LOGO_START) * 200;
+ if (logo_points < 0)
+ logo_points = 0;
+
+ IldaFile *ild = ctx;
+ int logo_idx = logo_points;
+ if (logo_idx >= ild->count)
+ logo_idx = ild->count - 1;
+
+ if (time < FADE_END) {
+ olPushColor();
+ olMultColor(C_GREY(maincolor < 0 ? 0 : maincolor));
+ olSetPixelShader(cutoff);
+
+ olBegin(OL_LINESTRIP);
+ olVertex3(-150, 10, 0, C_WHITE);
+ olVertex3(-190, 10, 0, C_WHITE);
+ olVertex3(-190, -10, 0, C_WHITE);
+ olVertex3(-150, -10, 0, C_WHITE);
+ olVertex3(-150, 10, 0, C_WHITE);
+ olEnd();
+ olBegin(OL_LINESTRIP);
+ olVertex3(-150, 7, 0, C_WHITE);
+ olVertex3(-140, 7, 0, C_WHITE);
+ olVertex3(-140, -7, 0, C_WHITE);
+ olVertex3(-150, -7, 0, C_WHITE);
+ olEnd();
+
+ point_step = 4;
+
+ olDrawString(olGetDefaultFont(), -185, 6, 14, C_WHITE, "Laser");
+
+ point_step = 20;
+ delay += 1000;
+
+ float px = 50 * ild->points[logo_idx].x;
+ float py = 50 * ild->points[logo_idx].y;
+
+ olBegin(OL_LINESTRIP);
+ olVertex3(-140, 0, 0, C_WHITE);
+ olVertex3(0, 0, 0, C_WHITE);
+ olVertex3(px / 20, 0, 15, C_WHITE);
+ olVertex3(px, 140, py, C_WHITE);
+ olEnd();
+
+ draw_galvo();
+ olPushMatrix3();
+ olTranslate3(0, 0, 15);
+ olRotate3Z(M_PI/2);
+ delay += 200;
+ draw_galvo();
+ olPopMatrix3();
+
+ delay += 1000;
+
+ point_step = 20;
+
+ olPopColor();
+
+ }
+
+ olSetPixelShader(NULL);
+ point_step = 10;
+ olBegin(OL_LINESTRIP);
+ olVertex3(-50, 140, 37.5, C_WHITE);
+ olVertex3(50, 140, 37.5, C_WHITE);
+ olVertex3(50, 140, -37.5, C_WHITE);
+ olVertex3(-50, 140, -37.5, C_WHITE);
+ olVertex3(-50, 140, 37.5, C_WHITE);
+ olEnd();
+
+ olTranslate3(0, 140, 0);
+ olScale3(50, 50, 50);
+ olRotate3X(M_PI/2);
+
+ if (logo_points > 0) {
+ delay = delay_ctr = 0;
+ points_left = logo_points;
+ point_step = 1;
+ olSetPixelShader(cutoff);
+ olDrawIlda3D(ctx);
+ }
+ olSetPixelShader(NULL);
+}
+
+
--- /dev/null
+
+
+find_package(Curses REQUIRED)
+
+include_directories(${CMAKE_SOURCE_DIR}/tools ${CURSES_INCLUDE_DIR})
+
+add_executable(slides
+ main.c 3ddemos.c static.c metaballs.c circlescope.c avstream.c video.c pong.c
+ ${CMAKE_SOURCE_DIR}/tools/trace.c
+
+ ${CMAKE_CURRENT_BINARY_DIR}/openlase-logo.ild
+ ${CMAKE_CURRENT_BINARY_DIR}/27c3-logo.ild
+ ${CMAKE_CURRENT_BINARY_DIR}/jack-logo.ild
+ ${CMAKE_CURRENT_BINARY_DIR}/output.ild
+)
+
+target_link_libraries(slides openlase avformat avcodec ${CURSES_LIBRARIES})
+
+function(svg2ild NAME)
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.ild
+ DEPENDS ${CMAKE_SOURCE_DIR}/tools/svg2ild.py
+ MAIN_DEPENDENCY ${NAME}.svg
+ DEPENDS ${NAME}.svg ${NAME}.cfg
+ COMMAND python ${CMAKE_SOURCE_DIR}/tools/svg2ild.py -q ${ARGN} -cfg ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.cfg ${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.svg ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.ild)
+endfunction()
+
+svg2ild(openlase-logo -noopt)
+svg2ild(27c3-logo)
+svg2ild(jack-logo)
+svg2ild(output)
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/* Simple wrapper around libavcodec to provide audio/video streams */
+
+static int inited = 0;
+
+#include "libol.h"
+#include "avstream.h"
+
+#define AUDIO_BUF AVCODEC_MAX_AUDIO_FRAME_SIZE
+
+static void dolog(void *foo, int level, const char *fmt, va_list ap)
+{
+ char buf[1024];
+ vsnprintf(buf, 1024, fmt, ap);
+ buf[1023] = 0;
+ olLog("%s", buf);
+}
+
+static void avstream_init(void)
+{
+ av_log_set_callback(dolog);
+ av_register_all();
+ inited = 1;
+}
+
+int video_readframe(VContext *ctx, AVFrame **oFrame)
+{
+ static AVPacket packet;
+ int bytesDecoded;
+ int frameFinished = 0;
+
+ while (!frameFinished) {
+ do {
+ if(av_read_frame(ctx->av.formatctx, &packet)<0) {
+ *oFrame = ctx->frame;
+ return 0;
+ }
+ } while(packet.stream_index!=ctx->av.stream);
+
+ bytesDecoded=avcodec_decode_video2(ctx->av.codecctx, ctx->frame, &frameFinished, &packet);
+ if (bytesDecoded < 0)
+ {
+ olLog("Error while decoding video frame\n");
+ *oFrame = ctx->frame;
+ return 0;
+ }
+ if (bytesDecoded != packet.size) {
+ olLog("Multiframe packets not supported (%d != %d)\n", bytesDecoded, packet.size);
+ exit(1);
+ }
+ }
+ *oFrame = ctx->frame;
+ return 1;
+}
+
+int audio_readsamples(AContext *ctx, float *lb, float *rb, int samples)
+{
+ AVPacket packet;
+ int bytes, bytesDecoded;
+ int input_samples;
+ int total = 0;
+ while (samples)
+ {
+ if (!ctx->buffered_samples) {
+ do {
+ if(av_read_frame(ctx->av.formatctx, &packet)<0) {
+ memset(lb, 0, samples*sizeof(float));
+ memset(rb, 0, samples*sizeof(float));
+ return total;
+ }
+ } while(packet.stream_index!=ctx->av.stream);
+
+ bytes = AUDIO_BUF * sizeof(short);
+
+ bytesDecoded = avcodec_decode_audio3(ctx->av.codecctx, ctx->iabuf, &bytes, &packet);
+ if(bytesDecoded < 0)
+ {
+ olLog("Error while decoding audio frame\n");
+ memset(lb, 0, samples*sizeof(float));
+ memset(rb, 0, samples*sizeof(float));
+ return -1;
+ }
+
+ input_samples = bytes / (sizeof(short)*ctx->av.codecctx->channels);
+
+ ctx->buffered_samples = audio_resample(ctx->resampler, (void*)ctx->oabuf, ctx->iabuf, input_samples);
+ ctx->poabuf = ctx->oabuf;
+ }
+
+ *lb++ = *ctx->poabuf++;
+ *rb++ = *ctx->poabuf++;
+ ctx->buffered_samples--;
+ samples--;
+ total++;
+ }
+ return total;
+}
+
+int video_open(VContext **octx, char *file)
+{
+ int i;
+ VContext *ctx;
+
+ if (!inited)
+ avstream_init();
+
+ ctx = malloc(sizeof(VContext));
+
+ if (av_open_input_file(&ctx->av.formatctx, file, NULL, 0, NULL) != 0)
+ goto error;
+
+ if (av_find_stream_info(ctx->av.formatctx) < 0)
+ goto error;
+
+ dump_format(ctx->av.formatctx, 0, file, 0);
+
+ int stream=-1;
+ for (i=0; i<ctx->av.formatctx->nb_streams; i++) {
+ if (ctx->av.formatctx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
+ stream=i;
+ break;
+ }
+ }
+ if (stream==-1)
+ goto error;
+
+ ctx->av.stream = stream;
+ ctx->av.codecctx = ctx->av.formatctx->streams[stream]->codec;
+ ctx->av.codec = avcodec_find_decoder(ctx->av.codecctx->codec_id);
+
+ if (ctx->av.codec == NULL)
+ goto error;
+
+ if (avcodec_open(ctx->av.codecctx, ctx->av.codec) < 0)
+ goto error;
+
+ ctx->frame = avcodec_alloc_frame();
+
+ *octx = ctx;
+ return 0;
+
+error:
+ // todo: cleanup avcodec stuff...
+ free(ctx);
+ *octx = NULL;
+ return -1;
+}
+
+int video_close(VContext *ctx)
+{
+ av_free(ctx->frame);
+ avcodec_close(ctx->av.codecctx);
+ av_close_input_file(ctx->av.formatctx);
+ free(ctx);
+
+ return 0;
+}
+
+int audio_open(AContext **octx, char *file)
+{
+ int i;
+ AContext *ctx;
+
+ if (!inited)
+ avstream_init();
+
+ ctx = malloc(sizeof(AContext));
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->oabuf = malloc(AUDIO_BUF * sizeof(float));
+ ctx->iabuf = malloc(AUDIO_BUF * sizeof(short));
+
+ if (av_open_input_file(&ctx->av.formatctx, file, NULL, 0, NULL) != 0)
+ goto error;
+
+ if (av_find_stream_info(ctx->av.formatctx) < 0)
+ goto error;
+
+ dump_format(ctx->av.formatctx, 0, file, 0);
+
+ int stream=-1;
+ for (i=0; i<ctx->av.formatctx->nb_streams; i++) {
+ if (ctx->av.formatctx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO) {
+ stream=i;
+ break;
+ }
+ }
+ if (stream==-1)
+ goto error;
+
+ ctx->av.stream = stream;
+ ctx->av.codecctx = ctx->av.formatctx->streams[stream]->codec;
+ ctx->av.codec = avcodec_find_decoder(ctx->av.codecctx->codec_id);
+
+ if (ctx->av.codec == NULL)
+ goto error;
+
+ if (avcodec_open(ctx->av.codecctx, ctx->av.codec) < 0)
+ goto error;
+
+ ctx->resampler = av_audio_resample_init(2, ctx->av.codecctx->channels,
+ 48000, ctx->av.codecctx->sample_rate,
+ SAMPLE_FMT_FLT, ctx->av.codecctx->sample_fmt,
+ 16, 10, 0, 0.8);
+
+ if (!ctx->resampler)
+ goto error;
+
+ ctx->buffered_samples = 0;
+
+ *octx = ctx;
+ return 0;
+error:
+ if (ctx->oabuf)
+ free(ctx->oabuf);
+ if (ctx->iabuf)
+ free(ctx->iabuf);
+ // todo: cleanup avcodec stuff...
+ free(ctx);
+ *octx = NULL;
+ return -1;
+}
+
+int audio_close(AContext *ctx)
+{
+ avcodec_close(ctx->av.codecctx);
+ audio_resample_close(ctx->resampler);
+ av_close_input_file(ctx->av.formatctx);
+ free(ctx->oabuf);
+ free(ctx->iabuf);
+ free(ctx);
+ return 0;
+}
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef AVSTREAM_H
+#define AVSTREAM_H
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+
+struct avfctx {
+ AVFormatContext *formatctx;
+ AVCodecContext *codecctx;
+ AVCodec *codec;
+ int stream;
+};
+
+struct _acontext {
+ struct avfctx av;
+ ReSampleContext *resampler;
+ float *oabuf;
+ short *iabuf;
+ int buffered_samples;
+ float *poabuf;
+};
+
+struct _vcontext {
+ struct avfctx av;
+ AVFrame *frame;
+};
+
+typedef struct _acontext AContext;
+typedef struct _vcontext VContext;
+
+int video_open(VContext **ctx, char *file);
+int video_readframe(VContext *ctx, AVFrame **oFrame);
+int video_close(VContext *ctx);
+
+int audio_open(AContext **ctx, char *file);
+int audio_readsamples(AContext *ctx, float *lb, float *rb, int samples);
+int audio_close(AContext *ctx);
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "libol.h"
+#include "ilda.h"
+#include "text.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avstream.h"
+
+/* This is a libol version of the circlescope, rendering audio from a file.
+ * Instead of taking audio from JACK, this uses the avstream.h stuff. Since this
+ * is based on libol, the audio and video are no longer sample-synchronous
+ * (as the image is just one object in the frame) so we drop/dupe samples as
+ * needed */
+
+static AContext *actx;
+static int got_samples = 0;
+static uint64_t sample_counter;
+
+#define DRAW_SAMPLES 1024
+
+static float lbuf[DRAW_SAMPLES];
+static float rbuf[DRAW_SAMPLES];
+
+static float volume = 0.8;
+
+void circlescope_init(void **ctx, void *arg, OLRenderParams *params)
+{
+ if (audio_open(&actx, arg) != 0) {
+ olLog("Audio open/init failed\n");
+ exit(1);
+ }
+
+ got_samples = 0;
+ sample_counter = 0;
+}
+
+void circlescope_deinit(void *ctx)
+{
+ audio_close(actx);
+ olSetAudioCallback(NULL);
+}
+
+static void moreaudio(float *lb, float *rb, int samples)
+{
+ int left = samples;
+ float *plb = lb, *prb = rb;
+
+ memset(lb, 0, sizeof(float)*samples);
+ memset(rb, 0, sizeof(float)*samples);
+
+ //audio_readleft(actx, lb, rb, left);
+ if (got_samples == 0) {
+ olLog("No audio buffer?\n");
+ return;
+ }
+
+
+ int copy = samples > got_samples ? got_samples : samples;
+
+ memcpy(lb, lbuf, copy * sizeof(float));
+ memcpy(rb, rbuf, copy * sizeof(float));
+ got_samples -= copy;
+ left -= copy;
+ plb += copy;
+ prb += copy;
+
+ if (got_samples) {
+ olLog("Had %d audio samples leftover...\n", got_samples);
+ memmove(lbuf, &lbuf[copy], got_samples * sizeof(float));
+ memmove(rbuf, &rbuf[copy], got_samples * sizeof(float));
+ }
+
+ if (left) {
+ olLog("Needed %d extra audio samples\n", left);
+ if (audio_readsamples(actx, plb, prb, left) < 1) {
+ olLog("No more audio!\n");
+ }
+ }
+
+ // unset the callback, it will be set by the render function again
+ olSetAudioCallback(NULL);
+
+ sample_counter += samples;
+
+ // adjust volume
+ int i;
+ for (i=0; i<samples; i++) {
+ lb[i] *= volume;
+ rb[i] *= volume;
+ }
+}
+
+#define MAX(a,b) (((a)<(b))?(b):(a))
+#define MIN(a,b) (((a)>(b))?(b):(a))
+
+float max_size = 0.75f;
+float min_size = 0.2f;
+float boost = 1.7;
+
+void circlescope_render(void *ctx, float time, float state)
+{
+ float pvol = (1-fabsf(state)*1.3);
+ volume = pvol < 0 ? 0 : 0.8 * pvol;
+
+ olLoadIdentity();
+
+ if (got_samples == DRAW_SAMPLES) {
+ olLog("Already got a full buffer?\n");
+ } else {
+ if (audio_readsamples(actx, &lbuf[got_samples], &rbuf[got_samples], DRAW_SAMPLES - got_samples) < 1) {
+ olLog("No more audio!\n");
+ }
+ got_samples = DRAW_SAMPLES;
+ }
+
+ int i;
+
+ olBegin(OL_POINTS);
+ for (i=0; i<DRAW_SAMPLES; i++) {
+ double w = 523.251131f / 4.0f * (2*M_PI) / 48000;
+ double pos = (sample_counter+i) * w;
+
+ float val = (lbuf[i] + rbuf[i]) / 2 * boost;
+ val = MAX(MIN(val,1.0f),-1.0f);
+ val = val * 0.5f + 0.5f;
+ val *= (max_size - min_size);
+ val += min_size;
+
+ olVertex(cosf(pos) * val, sinf(pos) * val, C_WHITE);
+ }
+ olEnd();
+
+
+ olSetAudioCallback(moreaudio);
+}
--- /dev/null
+on_speed = 2/100.0
+off_speed = 2/35.0
+flatness = 0.000001
+start_dwell = 3
+curve_dwell = 0
+corner_dwell = 5
+end_dwell = 2
+switch_dwell = 10
+closed_overdraw = 3
+closed_start_dwell = 0
+closed_end_dwell = 0
+extra_first_dwell = 0
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48+devel r"
+ width="470"
+ height="91"
+ sodipodi:docname="jack-logo.svg">
+ <metadata
+ id="metadata8">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1912"
+ inkscape:window-height="1005"
+ id="namedview4"
+ showgrid="false"
+ inkscape:zoom="13.070944"
+ inkscape:cx="405.77173"
+ inkscape:cy="51.634057"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" />
+ <path
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361731999999979;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 224.61192 18.778743 L 405.3265 18.778744 C 408.63245 18.778744 411.29393 21.440219 411.29393 24.746178 L 411.29393 61.16283 C 411.29393 64.468789 408.63245 67.130264 405.3265 67.130264 L 224.61193 67.130264 "
+ id="rect3071" />
+ <path
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 436.54077,18.625732 25.70586,14 c 2.9033,1.581205 5.96744,3.310647 5.96744,6.616606 l 0,3.928159 c 0,3.305958 -3.19264,5.360397 -5.96744,7.157581 l -25.70586,16.649171 c -2.7748,1.797184 -5.96744,-2.661476 -5.96744,-5.967434 l 0,-36.416648 c 0,-3.305959 3.06414,-7.54864 5.96744,-5.967435 z"
+ id="rect3073"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 411.41229,58.433241 19.09646,0"
+ id="path3076"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 411.41229,26.433241 19.09646,0"
+ id="path3076-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361731999999979;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 218.81981 11.742499 C 222.04799 11.830284 224.62036 14.457523 224.62036 17.707667 L 224.62036 72.179628 C 224.62036 75.429772 222.04799 78.057011 218.81981 78.144796 "
+ id="rect3096" />
+ <path
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 53.25701,78.912119 -40.557091,0 c -5.6794676,0 -10.2517464,-4.572279 -10.2517464,-10.251746 l 0,-45.597315 c 0,-5.679467 4.5722788,-10.251746 10.2517464,-10.251746 l 40.557091,0"
+ id="path3153"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssssc" />
+ <path
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-dashoffset:0;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 60.439392,1.6414981 151.174998,0 c 3.9841,0 7.19152,3.2074197 7.19152,7.191524 l 0,72.8332989 c 0,3.984104 -3.20742,7.191524 -7.19152,7.191524 l -151.174998,0 c -3.984105,0 -7.191524,-3.20742 -7.191524,-7.191524 l 0,-72.8332989 c 0,-3.9841043 3.207419,-7.191524 7.191524,-7.191524 z"
+ id="rect3096-6-5" />
+ <g
+ transform="matrix(0.94475761,0,0,1.0584726,0,10)"
+ style="font-size:58.49077225px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Arial;-inkscape-font-specification:Arial"
+ id="text3256">
+ <path
+ d="m 70.864573,42.036462 4.997991,-0.685438 c 0.133273,3.198723 0.733031,5.388317 1.799276,6.568787 1.066229,1.180483 2.541825,1.770721 4.426792,1.770717 1.389903,4e-6 2.58942,-0.314155 3.598553,-0.942478 1.009101,-0.647353 1.704059,-1.513671 2.084877,-2.598955 0.38078,-1.104309 0.571179,-2.855984 0.571199,-5.255031 l 0,-28.845547 5.540629,0 0,28.531388 c -2.4e-5,3.503363 -0.428423,6.216556 -1.285197,8.139585 -0.837781,1.92304 -2.180097,3.389116 -4.026953,4.398232 -1.827854,1.009118 -3.979368,1.513676 -6.454548,1.513677 -3.674722,-1e-6 -6.492634,-1.056718 -8.453744,-3.170154 -1.942079,-2.113432 -2.875037,-5.255023 -2.798875,-9.424783"
+ style="marker:none"
+ id="path3261"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 98.339242,53.9174 16.079248,-41.868883 5.96903,0 17.13597,41.868883 -6.31175,0 -4.88375,-12.680616 -17.50725,0 -4.59815,12.680616 -5.883348,0 m 12.080858,-17.193088 14.19429,0 -4.36967,-11.595339 c -1.33282,-3.522361 -2.32289,-6.416433 -2.97023,-8.682224 -0.53314,2.68467 -1.28522,5.350263 -2.25624,7.996786 l -4.59815,12.280777"
+ style="marker:none"
+ id="path3263"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 171.8811,39.237587 5.54063,1.399438 c -1.16147,4.55056 -3.25587,8.02535 -6.28318,10.424381 -3.00835,2.379996 -6.69258,3.569992 -11.0527,3.569993 -4.51249,-1e-6 -8.1872,-0.913918 -11.02414,-2.741755 -2.81793,-1.846873 -4.96944,-4.512465 -6.45455,-7.996785 -1.46608,-3.4843 -2.19912,-7.22565 -2.19912,-11.224059 0,-4.360127 0.82824,-8.158596 2.48472,-11.39542 1.67551,-3.255798 4.04598,-5.721471 7.11142,-7.397026 3.08446,-1.694515 6.47357,-2.541793 10.16735,-2.541835 4.18876,4.2e-5 7.71115,1.066279 10.56718,3.198714 2.85595,2.132513 4.84563,5.131305 5.96903,8.996383 l -5.45495,1.285198 c -0.97108,-3.046362 -2.38003,-5.264516 -4.22688,-6.654468 -1.8469,-1.38988 -4.16977,-2.084838 -6.96862,-2.084876 -3.21778,3.8e-5 -5.91193,0.771156 -8.08247,2.313356 -2.15153,1.542271 -3.6652,3.617625 -4.54103,6.226068 -0.87585,2.589462 -1.31377,5.264575 -1.31376,8.025346 -1e-5,3.560491 0.51407,6.673522 1.54224,9.339102 1.04719,2.646565 2.66558,4.626719 4.85519,5.940469 2.18958,1.313763 4.56005,1.970641 7.11143,1.970637 3.10349,4e-6 5.731,-0.894874 7.88254,-2.684635 2.15149,-1.789748 3.60804,-4.445821 4.36967,-7.968226"
+ style="marker:none"
+ id="path3265"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 183.93341,53.9174 0,-41.868883 5.54063,0 0,20.763082 20.79164,-20.763082 7.51126,0 -17.56436,16.964609 18.33548,24.904274 -7.31134,0 -14.9083,-21.191481 -6.85438,6.683028 0,14.508453 -5.54063,0"
+ style="marker:none"
+ id="path3267"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ id="path3197-5-1"
+ style="color:#000000;fill:none;stroke:#00ff00;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 392.34278,67.206768 0,-48.351518 0.9863,0 0,48.351518 0.98631,0 0,-48.351518 0.9863,0 0,48.351518 0.9863,0 0,-48.351518 0.9863,0 0,48.351518 0.9863,0 0,-48.351518 0.9863,0 0,48.351518 0.9863,0 0,-48.351518"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+</svg>
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/* Slides for the 27C3 OpenLase Lightning Talk */
+
+/* NOTE: You need to edit this file with the circlescope audio file (the Super
+ * Mario Bros music in the talk) and the tracer video file (a crop of the
+ * Bad Apple, see http://www.youtube.com/watch?v=G3C-VevI36s ). You can of
+ * course use any other files, though for the tracer you'll likely have to
+ * tweak the vparms depending on its complexity. */
+
+#include "libol.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/select.h>
+#include <termios.h>
+#include <unistd.h>
+#include <curses.h>
+
+// 4:3 aspect presentation
+#define ASPECT 0.75
+
+typedef void (*init_cb)(void **context, void *arg, OLRenderParams *params);
+typedef void (*render_cb)(void *context, float stime, float state);
+typedef void (*deinit_cb)(void *context);
+
+typedef struct {
+ render_cb render;
+ init_cb init;
+ deinit_cb deinit;
+ void *arg;
+ void *context;
+} slide_t;
+
+#include "video.h"
+
+video_params vparms = {
+ .file = "/home/marcansoft/dwhelper/bad_apple_crop.flv",
+ .thresh_dark = 60,
+ .thresh_light = 160,
+ .sw_dark = 100,
+ .sw_light = 160,
+ .decimate = 2,
+ .volume = 0.5,
+
+ // these just override render parameters
+ .min_length = 6,
+ .start_wait = 8,
+ .end_wait = 3,
+ .off_speed = 2.0/24,
+ .snap_pix = 4,
+ .min_framerate = 29,
+};
+
+#define DECLARE_SLIDE(name) \
+ void name##_render(void *, float, float); \
+ void name##_init(void **, void *, OLRenderParams *); \
+ void name##_deinit(void *)
+
+#define SLIDE(name, param) {name##_render, name##_init, name##_deinit, param}
+
+DECLARE_SLIDE(pong);
+DECLARE_SLIDE(videotracer);
+DECLARE_SLIDE(cubes);
+DECLARE_SLIDE(metaballs);
+DECLARE_SLIDE(showilda);
+DECLARE_SLIDE(paintilda);
+DECLARE_SLIDE(diag);
+DECLARE_SLIDE(urls);
+DECLARE_SLIDE(libol);
+DECLARE_SLIDE(circlescope);
+
+slide_t slides[] = {
+ SLIDE(paintilda, "openlase-logo.ild"),
+ SLIDE(diag, NULL),
+ SLIDE(showilda, "jack-logo.ild"),
+ SLIDE(showilda, "output.ild"),
+ SLIDE(libol, NULL),
+ SLIDE(cubes, NULL),
+ SLIDE(pong, NULL),
+ SLIDE(circlescope, "/home/marcansoft/media/midi/smb1.mp3"),
+ SLIDE(metaballs, NULL),
+ SLIDE(videotracer, &vparms),
+ SLIDE(showilda, "27c3-logo.ild"),
+ SLIDE(urls, NULL),
+};
+
+OLRenderParams master_params;
+
+#define NUM_SLIDES ((int)(sizeof(slides)/sizeof(slides[0])))
+
+WINDOW *cur_win;
+
+void logger(const char *msg)
+{
+ wprintw(cur_win, "%s", msg);
+ wrefresh(cur_win);
+}
+
+/*
+ Since we can't directly pipe 2D OpenLase output back into the 3D renderer,
+ abuse olTransformVertex3 to perform a second perspective transform.
+*/
+float cubepos = 0;
+
+// distance from observer to front face of cube (determines FOV)
+#define FACEDEPTH 3
+
+void shader_cube(float *x, float *y, uint32_t *color)
+{
+ olPushMatrix3();
+ olLoadIdentity3();
+
+ // Shrink down the entire final image a bit, to avoid cutting off the cube's
+ // left and right corners while it's rotating. On a bitmap display (PC) this
+ // doesn't matter, but on the laser without shading it looks bad if the edge
+ // suddenly scissors off.
+ olScale3( 0.9, 0.9, 0.9);
+
+ // This transform sets it up so that it's identity at the cube's front face
+ // (z = -4)
+ olFrustum(-1, 1, -1, 1, FACEDEPTH, 100);
+
+ // Now figure out the z-position depending on the rotation of the cube, to
+ // make the frontmost edge always be full-height.
+ float theta = cubepos < 0 ? -cubepos : cubepos;
+ float zdelta = -1 - FACEDEPTH + 1 * (sinf(M_PI/4) - sinf(M_PI/4 + theta));
+ olTranslate3(0, 0, zdelta);
+
+ // Perform the rotation
+ olRotate3Y(cubepos);
+
+ // And finally transform the incoming vertex
+ float z = 1;
+ olTransformVertex3(x, y, &z);
+
+ olPopMatrix3();
+}
+
+#define TRANSITION_TIME 0.75f
+
+float gtime = 0;
+int frames = 0;
+
+float cur_stime = 0;
+int cur_slide = 0;
+float next_stime = 0;
+int next_slide = -1;
+float trans_time = 0;
+
+void go(int delta)
+{
+ if (next_slide != -1) {
+ //olLog("WARNING: attempted to change slide while transition active\n");
+ return;
+ }
+ next_slide = (cur_slide + NUM_SLIDES + delta) % NUM_SLIDES;
+ next_stime = 0;
+ trans_time = 0;
+ OLRenderParams params = master_params;
+ if (slides[next_slide].init) {
+ slides[next_slide].init(&slides[next_slide].context, slides[next_slide].arg, ¶ms);
+ }
+ olSetRenderParams(¶ms);
+}
+
+// this is a function of FACEDEPTH above
+#define VANISH 1.33
+#define ST_VANISH 1.45
+
+void render_slide(int num, float stime, int bcolor, float state)
+{
+ int scolor = (VANISH - fabsf(cubepos)) / VANISH * 400;
+ if (fabsf(cubepos) < VANISH) {
+ olSetPixelShader(NULL);
+ olSetVertex3Shader(NULL);
+ olLoadIdentity();
+ olLoadIdentity3();
+ olResetColor();
+ if (scolor < 255)
+ olMultColor(C_GREY(scolor));
+ if (bcolor > 0) {
+ // make sure the corners of the slide-rect are always nice and sharp
+ // even when the whole frame gets resampled to maintain framerate
+ OLRenderParams old, params;
+ olGetRenderParams(&old);
+ params = old;
+ params.start_dwell = 40;
+ params.corner_dwell = 40;
+ params.end_dwell = 40;
+ olSetRenderParams(¶ms);
+ olRect(-1, -ASPECT, 1, ASPECT, C_GREY(bcolor > 255 ? 255 : bcolor));
+ olSetRenderParams(&old);
+ }
+
+ slides[num].render(slides[num].context, stime, state * ST_VANISH);
+ }
+}
+
+void render_slides(void)
+{
+ int bcolor = 0;
+
+ if (next_slide == -1) {
+ cubepos = 0;
+ render_slide(cur_slide, cur_stime, bcolor, 0);
+ } else if (trans_time >= TRANSITION_TIME) {
+ if (slides[cur_slide].deinit)
+ slides[cur_slide].deinit(slides[cur_slide].context);
+ cur_slide = next_slide;
+ cur_stime = next_stime;
+ cubepos = 0;
+ render_slide(cur_slide, cur_stime, bcolor, 0);
+ next_slide = -1;
+ } else {
+ float raw_subpos = trans_time / TRANSITION_TIME;
+ // apply a sine function to make it accelerate/delecerate smoothly
+ float subpos = (sinf((raw_subpos - 0.5) * M_PI) + 1)/2;
+
+ if (subpos < 0.5)
+ bcolor = subpos * 1200;
+ else
+ bcolor = (1-subpos) * 1200;
+
+ bcolor = bcolor > 0 ? bcolor + 0.3 : 0;
+
+ if (next_slide >= cur_slide)
+ cubepos = -subpos * M_PI/2;
+ else
+ cubepos = subpos * M_PI/2;
+ render_slide(cur_slide, cur_stime, bcolor, raw_subpos);
+
+ if (next_slide >= cur_slide)
+ cubepos = (1-subpos) * M_PI/2;
+ else
+ cubepos = (subpos-1) * M_PI/2;
+ render_slide(next_slide, next_stime, bcolor, raw_subpos-1);
+ }
+
+ float ftime = olRenderFrame(100);
+ frames++;
+ gtime += ftime;
+ cur_stime += ftime;
+ next_stime += ftime;
+ trans_time += ftime;
+
+ OLFrameInfo info;
+ olGetFrameInfo(&info);
+ mvprintw(3, 0, "Frame time: %f, Cur FPS: %f, Avg FPS: %f, Objects: %3d, Points: %d", ftime, 1/ftime, frames/gtime, info.objects, info.points);
+ if (info.resampled_points)
+ printw(", Rp: %4d, Bp: %4d", info.resampled_points, info.resampled_blacks);
+ if (info.padding_points)
+ printw(", Pad %4d", info.padding_points);
+ clrtoeol();
+ refresh();
+}
+
+WINDOW *misc_win, *render_win;
+
+void reset_term(void)
+{
+ delwin(misc_win);
+ delwin(render_win);
+ endwin();
+}
+
+#define WINSTART 5
+
+int main (int argc, char *argv[])
+{
+ initscr();
+ cbreak();
+ curs_set(0);
+ keypad(stdscr, TRUE);
+ nodelay(stdscr, TRUE);
+
+ int wh = (LINES - WINSTART)/2;
+
+ attron(A_BOLD);
+ render_win = newwin(wh-1, COLS, WINSTART + 1, 0);
+ scrollok(render_win, TRUE);
+ mvprintw(WINSTART, 0, "Render messages:");
+
+ misc_win = newwin(wh-1, COLS, WINSTART + wh + 1, 0);
+ scrollok(misc_win, TRUE);
+ mvprintw(WINSTART + wh, 0, "Misc messages:");
+ attroff(A_BOLD);
+
+ mvprintw(0, 0, "Keys: NEXT: -> or space PREV: <- QUIT: q\n");
+
+ refresh();
+
+ cur_win = misc_win;
+ olSetLogCallback(logger);
+
+ memset(&master_params, 0, sizeof master_params);
+ master_params.rate = 48000;
+ master_params.on_speed = 2.0/100.0;
+ master_params.off_speed = 2.0/55.0;
+ master_params.start_wait = 12;
+ master_params.start_dwell = 3;
+ master_params.curve_dwell = 0;
+ master_params.corner_dwell = 8;
+ master_params.curve_angle = cosf(30.0*(M_PI/180.0)); // 30 deg
+ master_params.end_dwell = 3;
+ master_params.end_wait = 7;
+ master_params.snap = 1/100000.0;
+ master_params.max_framelen = master_params.rate / 30;
+ master_params.flatness = 0.000001;
+ master_params.render_flags = RENDER_GRAYSCALE;
+
+ if(olInit(4, 100000) < 0)
+ return 1;
+
+ atexit(reset_term);
+
+ olSetVertexShader(shader_cube);
+
+ olSetScissor (-1, -ASPECT, 1, ASPECT);
+
+ //olLog("\e[6H");
+ OLRenderParams params = master_params;
+ if (slides[0].init)
+ slides[0].init(&slides[0].context, slides[0].arg, ¶ms);
+ olSetRenderParams(¶ms);
+
+ int done = 0;
+ while (!done) {
+ if (next_slide == -1) {
+ mvprintw(1, 0, "Slide %d/%d", cur_slide+1, NUM_SLIDES);
+ } else {
+ mvprintw(1, 0, "Slide %d/%d -> %d/%d", cur_slide+1, NUM_SLIDES, next_slide+1, NUM_SLIDES);
+ }
+ clrtoeol();
+ refresh();
+
+ fd_set rfds;
+ struct timeval tv;
+ tv.tv_sec = tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(0, &rfds);
+
+ while(1) {
+ int ch = getch();
+ if (ch == ERR)
+ break;
+ switch (ch) {
+ case KEY_LEFT:
+ go(-1);
+ break;
+ case KEY_RIGHT:
+ case ' ':
+ go(1);
+ break;
+ case 'q':
+ done = 1;
+ }
+
+ }
+
+ cur_win = render_win;
+ render_slides();
+ cur_win = misc_win;
+ }
+
+ olShutdown();
+ exit (0);
+}
+
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "libol.h"
+#include "ilda.h"
+#include "text.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+/* metaballs demo */
+
+/* This is the original quick&dirty metaballs tracer. The new one optimized for
+ * video is in trace.c. It's still dirty, but no longer that quick. */
+#define ABS(a) ((a)<0?(-(a)):(a))
+
+#define OVERDRAW 8
+
+static int trace(int *field, uint8_t *tmp, int thresh, int w, int h, int decimate)
+{
+ int x, y, cx, cy, px, py, i;
+ int iters = 0;
+ int objects = 0;
+ int sx[OVERDRAW], sy[OVERDRAW];
+
+ memset(tmp, 0, w*h);
+
+ for (y=1; y<h-1; y++) {
+ for (x=1; x<w-1;x++) {
+ int idx = y*w+x;
+ if (field[idx] > thresh && (!(field[idx-w] > thresh)
+ || !(field[idx+w] > thresh)
+ || !(field[idx-1] > thresh)
+ || !(field[idx+1] > thresh))) {
+ tmp[idx] = 1;
+ }
+ }
+ }
+
+ int total = h*w;
+ int dir = 0;
+ int minx = 0, miny = 0;
+ int maxx = w-1, maxy = h-1;
+ int div = 0;
+
+ px = 0;
+ py = 0;
+ while (total--)
+ {
+ if (tmp[py*w+px]) {
+ x = cx = px;
+ y = cy = py;
+ iters = 0;
+ olBegin(OL_POINTS);
+ while (1)
+ {
+ int idx = y*w+x;
+ if(div==0) {
+ if (iters < OVERDRAW) {
+ sx[iters] = x;
+ sy[iters] = y;
+ }
+ olVertex(x, y, C_WHITE);
+ iters++;
+ }
+ div = (div+1)%decimate;
+ tmp[idx] = 0;
+ if (tmp[idx-1]) {
+ x--;
+ } else if (tmp[idx+1]) {
+ x++;
+ } else if (tmp[idx-w]) {
+ y--;
+ } else if (tmp[idx+w]) {
+ y++;
+ } else if (tmp[idx-w-1]) {
+ y--; x--;
+ } else if (tmp[idx-w+1]) {
+ y--; x++;
+ } else if (tmp[idx+w-1]) {
+ y++; x--;
+ } else if (tmp[idx+w+1]) {
+ y++; x++;
+ } else {
+ break;
+ }
+
+ }
+ if (iters) {
+ objects++;
+ if (ABS(cx-x) <= 1 && ABS(cy-y) <= 1) {
+ if (iters > OVERDRAW)
+ iters = OVERDRAW;
+ for (i=0; i<iters; i++)
+ olVertex(sx[i], sy[i], C_GREY((int)(255.0 * (OVERDRAW - 1 - i) / (float)OVERDRAW)));
+ }
+ }
+ olEnd();
+ }
+ switch(dir) {
+ case 0:
+ px++;
+ if (px > maxx) {
+ px--; py++; maxx--; dir++;
+ }
+ break;
+ case 1:
+ py++;
+ if (py > maxy) {
+ py--; px--; maxy--; dir++;
+ }
+ break;
+ case 2:
+ px--;
+ if (px < minx) {
+ px++; py--; minx++; dir++;
+ }
+ break;
+ case 3:
+ py--;
+ if (py < miny) {
+ py++; px++; miny++; dir=0;
+ }
+ break;
+ }
+ }
+ return objects;
+}
+
+
+void metaballs_init(void **ctx, void *arg, OLRenderParams *params)
+{
+ params->start_wait = 8;
+ params->start_dwell = 7;
+ params->end_dwell = 7;
+}
+
+void metaballs_deinit(void *ctx)
+{
+}
+
+static int mbuf[192][256];
+static uint8_t mtmp[192][256];
+
+static void draw_metaball(float x, float y, float radius)
+{
+ int cx,cy;
+ float px,py;
+ int *p = &mbuf[0][0];
+ px = -x;
+ py = -y / 256.0 * 192.0;
+
+ radius *= 400000.0f;
+
+ for(cy=0; cy<192; cy++) {
+ for(cx=0; cx<256;cx++) {
+ float d = px*px+py*py;
+ *p++ += radius/(d+1);
+ px++;
+ }
+ py++;
+ px = -x;
+ }
+}
+
+void metaballs_render(void *ctx, float time)
+{
+ float dist1 = 128 + sinf(time * M_PI * 1.0 * 0.8 * 0.8 + 0) * 95;
+ float dist2 = 128 + sinf(time * M_PI * 1.2 * 0.8 * 0.8 + 1) * 95;
+ float dist3 = 130 + sinf(time * M_PI * 1.3 * 0.8 * 0.8 + 2) * 95;
+ float dist4 = 100 + sinf(time * M_PI * 1.4 * 0.8 * 0.8 + 3) * 95;
+ float dist5 = 128 + sinf(time * M_PI * 1.5 * 0.5 * 0.8 + 4) * 95;
+ float dist6 = 128 + sinf(time * M_PI * 1.6 * 0.5 * 0.8 + 5) * 95;
+ float dist7 = 130 + sinf(time * M_PI * 1.7 * 0.5 * 0.8 + 6) * 95;
+ float dist8 = 100 + sinf(time * M_PI * 1.8 * 0.5 * 0.8 + 7) * 95;
+ float dist9 = 130 + sinf(time * M_PI * 1.9 * 0.8 * 0.8 + 6) * 95;
+ float dist10 = 100 + sinf(time * M_PI * 2.0 * 0.5 * 0.8 + 7) * 95;
+
+ memset(mbuf, 0, sizeof mbuf);
+
+ draw_metaball(dist1, dist5, 45);
+ draw_metaball(dist2, dist6, 10);
+ draw_metaball(dist7, dist3, 30);
+ draw_metaball(dist8, dist4, 70);
+ draw_metaball(dist9, dist10, 70);
+
+ olPushMatrix();
+ olTranslate(-1.0f, -0.75f);
+ olScale(2.0f/256.0f, 2.0f/256.0f);
+
+ trace(&mbuf[0][0], &mtmp[0][0], 20000, 256, 192, 1);
+
+ olPopMatrix();
+ return;
+}
--- /dev/null
+on_speed = 2/90.0
+off_speed = 2/20.0
+flatness = 1
+start_dwell = 7
+curve_dwell = 0
+corner_dwell = 8
+end_dwell = 4
+switch_dwell = 9
+closed_overdraw = 0
+closed_start_dwell = 7
+closed_end_dwell = 4
+extra_first_dwell = 10
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1640"
+ height="440"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48+devel r"
+ sodipodi:docname="openlase-logo.svg">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.35"
+ inkscape:cx="1433.287"
+ inkscape:cy="61.149503"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:window-width="1912"
+ inkscape:window-height="1005"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:snap-nodes="true"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2816"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true"
+ spacingx="20px"
+ spacingy="20px" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(701.5,-313.86218)">
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m -681.5,333.86218 1600,0"
+ id="path2860"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m -681.5,733.86218 1600,0"
+ id="path2862"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ transform="translate(-1381.5,33.862189)"
+ sodipodi:type="arc"
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path3325"
+ sodipodi:cx="800"
+ sodipodi:cy="500"
+ sodipodi:rx="100"
+ sodipodi:ry="160"
+ d="m 900,500 a 100,160 0 1 1 -200,0 100,160 0 1 1 200,0 z" />
+ <path
+ id="path3351"
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m -481.5,533.86218 100,0 c 44.18278,0 80,-35.81722 80,-80 0,-44.18278 -35.81722,-80 -80,-80 l -100,0 0,320"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsccc" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m -101.5,373.86218 -200,0 0,320 200,0"
+ id="path2870-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m -301.5,533.86219 120,0"
+ id="path3382"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m -101.5,693.86218 0,-320 200,320 0,-320"
+ id="path3386"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 118.5,373.86218 0,320 160,0 120,-320 120,320"
+ id="path2864"
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path3302-9"
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 528.5,613.86218 c 0,44.18278 34.77153,80 90,80 55.22847,0 100,-35.81722 100,-80 0,-44.18278 -44.77153,-80 -100,-80 -55.22847,0 -100,-35.81722 -100,-80 0,-44.18278 44.77153,-80 100,-80 55.22847,0 120,20 90,80"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csscssc" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 918.5,373.86218 -200,0 0,320 200,0"
+ id="path2870"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 118.5,533.86218 760,0"
+ id="path2872"
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 818.5,473.86218 0,120"
+ id="path2884"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 778.5,493.86218 80,80"
+ id="path2886"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="color:#000000;fill:none;stroke:#00c300;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 778.5,573.86218 80,-80"
+ id="path2888"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+</svg>
--- /dev/null
+on_speed = 2/200.0
+off_speed = 2/25.0
+flatness = 0.0000001
+start_dwell = 10
+curve_dwell = 0
+corner_dwell = 20
+end_dwell = 10
+switch_dwell = 6
+closed_overdraw = 16
+closed_start_dwell = 10
+closed_end_dwell = 10
+extra_first_dwell = 0
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="225"
+ height="165"
+ id="svg3142"
+ version="1.1"
+ inkscape:version="0.48+devel r"
+ sodipodi:docname="output.svg">
+ <defs
+ id="defs3144" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.4"
+ inkscape:cx="165.78848"
+ inkscape:cy="93.596254"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-width="1912"
+ inkscape:window-height="1005"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3158"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata3147">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-334.49938,-302.87499)">
+ <rect
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3160"
+ width="85"
+ height="80"
+ x="384.49939"
+ y="322.875" />
+ <rect
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3930"
+ width="25"
+ height="5"
+ x="479.49939"
+ y="322.875" />
+ <rect
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3932"
+ width="135"
+ height="135"
+ x="379.49939"
+ y="317.875" />
+ <rect
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3930-1"
+ width="25"
+ height="5"
+ x="479.49939"
+ y="332.875" />
+ <path
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 394.49937,387.87498 5,-55 1,0 0,1 -2,0 0,-2 2,0 0,1 -1,0 55,-5 -1,0 0,-1 2,0 0,2 -2,0 0,-1 1,0 5,55 -1,0 0,1 2,0 0,-2 -2,0 0,1 1,0 -65,5 1,0 0,-1 -2,0 0,2 2,0 0,-1 z"
+ id="path4161"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 394.49937,407.87498 5,5 -10,0 5,-5 0,14 -4,0 8,0 -4,0 0,26 5,-5 -10,0 5,5"
+ id="path4167"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ <path
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 499.49937,407.87498 5,5 -10,0 5,-5 0,10 -4,0 8,0 -4,0 0,30 5,-5 -10,0 5,5"
+ id="path4167-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ <path
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 464.49937,407.87498 5,5 -10,0 5,-5 0,22 -4,0 8,0 -4,0 0,18 5,-5 -10,0 5,5"
+ id="path4167-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ <path
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 429.49937,407.87498 5,5 -10,0 5,-5 0,28 -4,0 8,0 -4,0 0,12 5,-5 -10,0 5,5"
+ id="path4167-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ <path
+ sodipodi:type="arc"
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4201"
+ sodipodi:cx="117.5"
+ sodipodi:cy="42.5"
+ sodipodi:rx="2.5"
+ sodipodi:ry="2.5"
+ d="m 120,42.5 a 2.5,2.5 0 1 1 -5,0 2.5,2.5 0 1 1 5,0 z"
+ transform="translate(364.49937,302.87498)" />
+ <path
+ transform="translate(364.49937,312.87498)"
+ sodipodi:type="arc"
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4201-4"
+ sodipodi:cx="117.5"
+ sodipodi:cy="42.5"
+ sodipodi:rx="2.5"
+ sodipodi:ry="2.5"
+ d="m 120,42.5 a 2.5,2.5 0 1 1 -5,0 2.5,2.5 0 1 1 5,0 z" />
+ <path
+ transform="translate(364.49937,322.87498)"
+ sodipodi:type="arc"
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4201-9"
+ sodipodi:cx="117.5"
+ sodipodi:cy="42.5"
+ sodipodi:rx="2.5"
+ sodipodi:ry="2.5"
+ d="m 120,42.5 a 2.5,2.5 0 1 1 -5,0 2.5,2.5 0 1 1 5,0 z" />
+ <path
+ transform="translate(364.49937,342.87498)"
+ sodipodi:type="arc"
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4201-9-5"
+ sodipodi:cx="117.5"
+ sodipodi:cy="42.5"
+ sodipodi:rx="2.5"
+ sodipodi:ry="2.5"
+ d="m 120,42.5 a 2.5,2.5 0 1 1 -5,0 2.5,2.5 0 1 1 5,0 z" />
+ <path
+ transform="translate(364.49937,352.87498)"
+ sodipodi:type="arc"
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4201-8-5"
+ sodipodi:cx="117.5"
+ sodipodi:cy="42.5"
+ sodipodi:rx="2.5"
+ sodipodi:ry="2.5"
+ d="m 120,42.5 a 2.5,2.5 0 1 1 -5,0 2.5,2.5 0 1 1 5,0 z" />
+ <rect
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.97361732;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3930-1-1"
+ width="25"
+ height="5"
+ x="479.49939"
+ y="372.875" />
+ </g>
+</svg>
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "libol.h"
+#include "ilda.h"
+#include "text.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* pong demo */
+
+#define TOP 0.25
+#define BOTTOM 0.85
+#define LEFT 0.07
+#define RIGHT 0.93
+#define WIDTH (RIGHT-LEFT)
+#define HEIGHT (BOTTOM-TOP)
+#define PH 0.12
+#define PW 0.03
+#define BW 0.02
+#define BH 0.02
+
+static float p1,p2,bx,by,bdx,bdy;
+int score1, score2;
+int adv;
+
+static float ltime = 0;
+
+#define BDX 0.75
+#define BDY 0.4
+
+void pong_init(void **ctx, void *arg, OLRenderParams *params)
+{
+ params->render_flags |= RENDER_NOREVERSE;
+
+ p1 = (HEIGHT-PH)/2;
+ p2 = (HEIGHT-PH)/2;
+ bx = 0;
+ by = HEIGHT/2;
+ bdx = BDX;
+ bdy = BDY;
+
+ score1 = 0;
+ score2 = 0;
+ adv = random()%2;
+
+ ltime = -1;
+}
+
+void pong_deinit(void *ctx)
+{
+}
+
+void digit(float x, float y, int d, uint32_t color)
+{
+}
+
+void pong_render(void *ctx, float time)
+{
+ float ftime = time - ltime;
+
+ if (ltime == -1)
+ ftime = 0;
+ ltime = time;
+
+ bx += ftime*bdx;
+ by += ftime*bdy;
+
+ if (by > HEIGHT - BH) {
+ bdy = -bdy;
+ by += 2*ftime*bdy;
+ } else if (by < 0) {
+ bdy = -bdy;
+ by += 2*ftime*bdy;
+ }
+
+ float r1 = ((random()%100-50) / 10000.0);
+ float r2 = ((random()%100-50) / 10000.0);
+
+ float p1fac = powf((1-bx/WIDTH),2) * (adv?0.17:0.22) + 0.03 + r1;
+ float p2fac = powf(bx/WIDTH,2) * (adv?0.22:0.17) + 0.03 + r2;
+
+ p1 = p1 * (1-p1fac) + (by-PH/2) * p1fac;
+ p2 = p2 * (1-p2fac) + (by-PH/2) * p2fac;
+
+ if (p1 < 0)
+ p1 = 0;
+ if (p1 > HEIGHT-PH)
+ p1 = HEIGHT-PH;
+
+ if (p2 < 0)
+ p2 = 0;
+ if (p2 > HEIGHT-PH)
+ p2 = HEIGHT-PH;
+
+ olLog("%f %10f %10f %10f %10f %10f %10f\n", p1, p2, r1, r2, p1fac, p2fac, bx);
+
+ if (bx <= 0) {
+ if (by < p1-BH || by > p1+PH) {
+ if (bx < -BW) {
+ by = p2 + PH/2 - BH/2;
+ bx = WIDTH - BW;
+ bdx = -BDX;
+ bdy = BDY;
+ score2++;
+ adv = random()%2;
+ }
+ } else {
+ bdx = -bdx;
+ bx += 2*ftime*bdx;
+ }
+ } else if (bx > WIDTH - BW) {
+ if (by < p2-BH || by > p2+PH) {
+ if (bx > WIDTH) {
+ by = p1 + PH/2 - BH/2;
+ bx = 0;
+ bdx = BDX;
+ bdy = BDY;
+ score1++;
+ adv = random()%2;
+ }
+ } else {
+ bdx = -bdx;
+ bx += 2*ftime*bdx;
+ }
+ }
+
+ bdx *= powf(1.2, ftime);
+ bdy *= powf(1.2, ftime);
+
+
+
+ olLoadIdentity();
+
+ olTranslate(-1,1);
+ olScale(2,-2);
+ // window is now 0.0-1.0 X and Y, Y going down)
+ olRect(0, TOP, 1, BOTTOM, C_WHITE);
+ olRect(LEFT-PW, p1+TOP, LEFT, p1+TOP+PH, C_WHITE);
+ olRect(RIGHT, p2+TOP, RIGHT+PW, p2+TOP+PH, C_WHITE);
+ olRect(LEFT+bx, TOP+by, LEFT+bx+BW, TOP+by+BW, C_WHITE);
+ olLine((LEFT+RIGHT)/2, TOP, (LEFT+RIGHT)/2, BOTTOM, C_GREY(70));
+
+ olTranslate(0, TOP - 0.13);
+ olScale(1, -1);
+
+ char buf[10];
+ sprintf(buf, "%d", score1);
+ olDrawString(olGetDefaultFont(), LEFT, 0, 0.15, C_WHITE, buf);
+
+ sprintf(buf, "%d", score2);
+ float sw = olGetStringWidth(olGetDefaultFont(), 0.15, buf);
+ olDrawString(olGetDefaultFont(), RIGHT-sw, 0, 0.15, C_WHITE, buf);
+
+ //float sw = olGetS
+
+ /*
+ if (score1 >= 100)
+ digit(0,0,score1/100,C_WHITE);
+ if (score1 >= 10)
+ digit(DIGW,0,score1/10%10,C_WHITE);
+ digit(2*DIGW,0,score1%10,C_WHITE);
+
+ if (score2 >= 100)
+ digit(1-3*DIGW,0,score2/100,C_WHITE);
+ if (score2 >= 10)
+ digit(1-2*DIGW,0,score2/10%10,C_WHITE);
+ digit(1-1*DIGW,0,score2%10,C_WHITE);*/
+}
--- /dev/null
+on_speed = 2/100.0
+off_speed = 2/25.0
+flatness = 0.000001
+start_dwell = 4
+curve_dwell = 0
+corner_dwell = 5
+end_dwell = 4
+switch_dwell = 6
+closed_overdraw = 3
+closed_start_dwell = 3
+closed_end_dwell = 3
+extra_first_dwell = 0
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "libol.h"
+#include "ilda.h"
+#include "text.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void showilda_init(void **ctx, void *param)
+{
+ *ctx = olLoadIlda(param);
+ if (!*ctx)
+ olLog("Failed to load %s\n", (char*)param);
+}
+
+void showilda_deinit(void *ctx)
+{
+ if (ctx)
+ olFreeIlda(ctx);
+}
+
+void showilda_render(void *ctx, float time)
+{
+ olLoadIdentity();
+ olDrawIlda(ctx);
+}
+
+int points_left = 0;
+int include_dark_points = 0;
+
+static void cutoff(float *x, float *y, uint32_t *color)
+{
+ static float save_x, save_y;
+ static uint32_t save_color;
+ static int points_dot = 0;
+ if ((!include_dark_points) && (*color == C_BLACK)) {
+ if (points_left)
+ return;
+ *x = save_x;
+ *y = save_y;
+ }
+ if (points_left) {
+ points_left--;
+ save_x = *x;
+ save_y = *y;
+ save_color = *color;
+ points_dot = 200;
+ } else {
+ *x = save_x;
+ *y = save_y;
+ if (points_dot) {
+ *color = C_WHITE;
+ points_dot--;
+ } else {
+ *color = C_BLACK;
+ }
+ }
+}
+
+void paintilda_init(void **ctx, void *param, OLRenderParams *params)
+{
+ *ctx = olLoadIlda(param);
+ if (!*ctx)
+ olLog("Failed to load %s\n", (char*)param);
+ params->render_flags |= RENDER_NOREVERSE;
+}
+
+void paintilda_deinit(void *ctx)
+{
+ if (ctx)
+ olFreeIlda(ctx);
+}
+
+void paintilda_render(void *ctx, float time)
+{
+ include_dark_points = 1;
+ points_left = time * 300;
+ olLoadIdentity();
+ olSetPixelShader(cutoff);
+ olDrawIlda(ctx);
+ olSetPixelShader(NULL);
+}
+
+
+void urls_init(void **ctx, void *param, OLRenderParams *params)
+{
+ params->on_speed = 2.0/100.0;
+ params->off_speed = 2.0/50.0;
+ params->start_wait = 7;
+ params->start_dwell = 0;
+ params->curve_dwell = 0;
+ params->corner_dwell = 8;
+ params->end_dwell = 0;
+ params->end_wait = 7;
+ params->flatness = 0.000005;
+ params->render_flags |= RENDER_NOREORDER;
+}
+
+void urls_deinit(void *ctx)
+{
+}
+
+void urls_render(void *ctx, float time)
+{
+ olLoadIdentity();
+ olLoadIdentity3();
+ olDrawString(olGetDefaultFont(), -0.99, 0.1, 0.25, C_WHITE, "marcansoft.com/openlase");
+}
+
+void libol_init(void **ctx, void *param, OLRenderParams *params)
+{
+ params->on_speed = 2.0/100.0;
+ params->off_speed = 2.0/50.0;
+ params->start_wait = 15;
+ params->start_dwell = 5;
+ params->curve_dwell = 0;
+ params->corner_dwell = 5;
+ params->end_dwell = 5;
+ params->end_wait = 2;
+ params->flatness = 0.000005;
+ params->render_flags |= RENDER_NOREORDER;
+}
+
+void libol_deinit(void *ctx)
+{
+}
+
+void libol_render(void *ctx, float time)
+{
+ olLoadIdentity();
+ olLoadIdentity3();
+ olDrawString(olGetDefaultFont(), -0.45, 0.45, 0.2, C_WHITE, "olBegin()");
+ olDrawString(olGetDefaultFont(), -0.50, 0.3, 0.8, C_WHITE, "libol");
+ olDrawString(olGetDefaultFont(), -0.45, -0.3, 0.2, C_WHITE, "olEnd()");
+}
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "libol.h"
+#include "ilda.h"
+#include "text.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avstream.h"
+#include "video.h"
+#include "trace.h"
+
+/* This is a slide version of playvid.c, using avstream.c. */
+
+static AContext *actx;
+static VContext *vctx;
+
+static video_params *cfg;
+
+static float vidtime;
+static void *tmp;
+static int dropframes;
+static int inframes;
+static int outframes;
+static float volume = 0;
+static int bg_white = -1;
+static AVFrame *frame;
+
+static void moreaudio(float *lb, float *rb, int samples)
+{
+ audio_readsamples(actx, lb, rb, samples);
+ while (samples--) {
+ *lb++ *= volume;
+ *rb++ *= volume;
+ }
+}
+
+void videotracer_init(void **ctx, void *arg, OLRenderParams *params)
+{
+ cfg = arg;
+ if (audio_open(&actx, cfg->file) != 0) {
+ olLog("Audio open/init failed\n");
+ exit(1);
+ }
+
+ if (video_open(&vctx, cfg->file) != 0) {
+ olLog("Video open/init failed\n");
+ exit(1);
+ }
+
+ int width = vctx->av.codecctx->width;
+ int height = vctx->av.codecctx->height;
+
+ if (cfg->aspect == 0)
+ cfg->aspect = width / (float)height;
+ if (cfg->framerate == 0)
+ cfg->framerate = vctx->av.formatctx->streams[vctx->av.stream]->r_frame_rate.num / (float)vctx->av.formatctx->streams[vctx->av.stream]->r_frame_rate.den;
+
+ tmp = malloc(width * height * 2);
+ vidtime = 0;
+ dropframes = 0;
+ inframes = 0;
+ outframes = 0;
+ bg_white = -1;
+ olSetAudioCallback(moreaudio);
+
+ int maxd = width > height ? width : height;
+
+ if (cfg->min_length)
+ params->min_length = cfg->min_length;
+ if (cfg->off_speed)
+ params->off_speed = cfg->off_speed;
+ if (cfg->start_wait)
+ params->start_wait = cfg->start_wait;
+ if (cfg->end_wait)
+ params->end_wait = cfg->end_wait;
+ if (cfg->snap_pix)
+ params->snap = (cfg->snap_pix*2.0)/(float)maxd;
+ if (cfg->min_framerate)
+ params->max_framelen = params->rate / cfg->min_framerate;
+}
+
+void videotracer_deinit(void *ctx)
+{
+ audio_close(actx);
+ video_close(vctx);
+ free(tmp);
+ olSetAudioCallback(NULL);
+}
+
+#define ASPECT 0.75
+
+void videotracer_render(void *ctx, float time, float state)
+{
+ float pvol = (1-fabsf(state));
+ volume = pvol < 0 ? 0 : 0.8 * pvol * cfg->volume;
+ olLog("state=%f pvol=%f\n", state, pvol);
+
+ float iaspect = 1/cfg->aspect;
+ int width = vctx->av.codecctx->width;
+ int height = vctx->av.codecctx->height;
+
+ if (cfg->aspect > ASPECT) {
+ olScale(1, iaspect);
+ } else {
+ olScale(ASPECT * cfg->aspect, ASPECT);
+ }
+
+ olScale(1+cfg->overscan, 1+cfg->overscan);
+ olTranslate(-1.0f, 1.0f);
+ olScale(2.0f/width, -2.0f/height);
+
+ float frametime = 1.0f/cfg->framerate;
+
+ while ((time+frametime) >= vidtime) {
+ if (video_readframe(vctx, &frame) != 1) {
+ olLog("Video EOF!\n");
+ return;
+ }
+ if (inframes == 0)
+ olLog("Frame stride: %d\n", frame->linesize[0]);
+
+ inframes++;
+ if (vidtime < time) {
+ vidtime += frametime;
+ //olLog("Frame skip!\n");
+ dropframes++;
+ continue;
+ }
+ vidtime += frametime;
+ }
+
+ int thresh;
+ int obj;
+ int bsum = 0;
+ int c;
+ for (c=cfg->edge_off; c<(width-cfg->edge_off); c++) {
+ bsum += frame->data[0][c+cfg->edge_off*frame->linesize[0]];
+ bsum += frame->data[0][c+(height-cfg->edge_off-1)*frame->linesize[0]];
+ }
+ for (c=cfg->edge_off; c<(height-cfg->edge_off); c++) {
+ bsum += frame->data[0][cfg->edge_off+c*frame->linesize[0]];
+ bsum += frame->data[0][(c+1)*frame->linesize[0]-1-cfg->edge_off];
+ }
+ bsum /= 2 * width * height;
+ if (bg_white == -1)
+ bg_white = bsum > 128;
+ if (bg_white && bsum < cfg->sw_dark)
+ bg_white = 0;
+ if (!bg_white && bsum > cfg->sw_light)
+ bg_white = 1;
+
+ if (bg_white)
+ thresh = cfg->thresh_light;
+ else
+ thresh = cfg->thresh_dark;
+
+ obj = trace(frame->data[0], tmp, thresh, width, height, frame->linesize[0], cfg->decimate);
+
+ outframes++;
+ olLog("Video stats: Drift %7.4f, In %4d, Out %4d, Drop %4d, Thr %3d, Bg %3d\n",
+ time-vidtime, inframes, outframes, dropframes, thresh, bsum);
+}
--- /dev/null
+/*
+ OpenLase - a realtime laser graphics toolkit
+
+Copyright (C) 2009-2010 Hector Martin "marcan" <hector@marcansoft.com>
+
+This program 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 2 or version 3.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef VIDEO_H
+#define VIDEO_H
+
+typedef struct {
+ char *file;
+ int thresh_dark;
+ int thresh_light;
+ int sw_dark;
+ int sw_light;
+ int edge_off;
+ int decimate;
+ float overscan;
+ float aspect;
+ float framerate;
+ float volume;
+
+ int min_length;
+ int start_wait;
+ int end_wait;
+ int off_speed;
+ int snap_pix;
+ float min_framerate;
+} video_params;
+
+#endif
\ No newline at end of file
add_executable(harp harp.c)
target_link_libraries(harp openlase)
+
+add_subdirectory(27c3_slides)