/* winnie - an experimental window system Copyright (C) 2013 Eleni Maria Stea 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 3 of the License, or (at your option) any later version. 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, see . Author: Eleni Maria Stea */ #include "tunneltex.h" #include "winnie.h" #include #include #include static void resize(int xsz, int ysz); static void display(Window *win); static void timer(Window *win); static bool calc_tunnel_mapping(); static int xsz = 512; static int ysz = 384; static Pixmap *tex; static float *umap, *vmap; static unsigned long start_time; extern "C" bool init() { Window *win = new Window; win->set_title("tunnel effect"); win->move(380, 280); win->resize(xsz, ysz); win->set_display_callback(display); win->set_timer_callback(timer); tex = new Pixmap; tex->set_image(gimp_image.width, gimp_image.height); for (int i = 0; i < tex->width * tex->height; i++) { tex->pixels[i * 4] = gimp_image.pixel_data[i * 3]; tex->pixels[i * 4 + 1] = gimp_image.pixel_data[i * 3 + 1]; tex->pixels[i * 4 + 2] = gimp_image.pixel_data[i * 3 + 2]; } resize(xsz, ysz); wm->add_window(win); start_time = winnie_get_time(); set_window_timer(win, 25, TIMER_REPEAT); return true; } extern "C" void cleanup() { delete tex; } static void resize(int width, int height) { xsz = width; ysz = height; calc_tunnel_mapping(); } static void display(Window *win) { Pixmap *fb = get_framebuffer_pixmap(); Rect wrect = win->get_absolute_rect(); if (wrect.width != xsz || wrect.height != ysz) { resize(wrect.width, wrect.height); } unsigned long msec = winnie_get_time() - start_time; float sec = (float) msec / 1000.0f; float uoffs = sec * 0.75; float voffs = sec; unsigned char *fbptr = fb->pixels + (wrect.y * fb->width + wrect.x) * 4; float *uptr = umap; float *vptr = vmap; for (int i = 0; i < ysz; i++) { for (int j = 0; j < xsz; j++) { float u = *uptr++ * 8.0f; float v = *vptr++; // unsigned long tx = ((((unsigned long)((u << 3) - uoffs)) & 0xff) * // tex->width) >> 8; unsigned long tx = ((((u << 3) * tex->width) >> 8) + // uoffs) % tex->width; unsigned long ty = (((unsigned long)(v + voffs * // 2) & 0xff) * tex->height) >> 8; int tx = fmod(u - uoffs, 1.0f) * tex->width; if (tx < 0) { tx += tex->width; } int ty = fmod(v + voffs, 1.0f) * tex->height; float fog = 1.0f - v / 8.0f; if (fog < 0.0f) fog = 0.0f; if (fog > 1.0f) fog = 1.0f; unsigned char red, green, blue; if (i == ysz / 2 && j == xsz / 2) { red = green = blue = 0; } else { int offs = (ty * tex->width + tx) * 4; red = tex->pixels[offs]; green = tex->pixels[offs + 1]; blue = tex->pixels[offs + 2]; } red = red * fog; green = green * fog; blue = blue * fog; fbptr[j * 4] = red; fbptr[j * 4 + 1] = green; fbptr[j * 4 + 2] = blue; } fbptr += fb->width * 4; } } static void timer(Window *win) { wm->invalidate_region(win->get_absolute_rect()); } static bool calc_tunnel_mapping() { int i, j; float *uptr, *vptr; if (umap || vmap) { free(umap); free(vmap); } if (!(umap = (float *) malloc(xsz * ysz * sizeof *umap))) { return false; } if (!(vmap = (float *) malloc(xsz * ysz * sizeof *umap))) { free(umap); return false; } uptr = umap; vptr = vmap; for (i = 0; i < ysz; i++) { for (j = 0; j < xsz; j++) { float x = ((float) j / xsz * 2.0 - 1.0) * 1.33333; float y = (float) i / ysz * 2.0 - 1.0; float angle, z, dist; if (fabs(x) > 0.00001) { angle = atan2(y, x) + M_PI; } else { angle = y < 0.0 ? M_PI / 2.0 : 3.0 * M_PI / 2.0; } dist = sqrt(x * x + y * y); z = 2.0 / dist; *uptr++ = angle * 0.5 / M_PI; *vptr++ = z; } } return true; }