1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
|
(***********************************************************************)
(* *)
(* Active-DVI *)
(* *)
(* Projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 2002 Institut National de Recherche en Informatique et *)
(* en Automatique. All rights reserved. This file is distributed *)
(* under the terms of the GNU Lesser General Public License. *)
(* *)
(* Jun Furuse, Didier Rmy and Pierre Weis. *)
(* Contributions by Roberto Di Cosmo, Didier Le Botlan, *)
(* Xavier Leroy, and Alan Schmitt. *)
(* *)
(* Based on Mldvi by Alexandre Miquel. *)
(***********************************************************************)
(* $Id: transimpl.ml,v 1.24 2004/09/15 16:37:55 weis Exp $ *)
open Transitions;;
(* Drawing (moving and resizing and ...) sprites on the screen. *)
let prev_geom = ref None;;
let init_sprite () = prev_geom := None;;
let do_on_screen = GraphicsY11.only_on_screen;;
let do_on_screen f x =
Graphics.remember_mode false;
GraphicsY11.display_mode true;
let r = f x in
GraphicsY11.display_mode false;
Graphics.remember_mode true;
r;;
let draw_sprite newimg x y width height =
let orgimg = Graphics.get_image x y width height in
let (wx, wy, wwidth, wheight) =
match !prev_geom with
| None -> x, y, width, height
| Some (x', y', width', height') ->
let x'' = min x x'
and y'' = min y y' in
let width'' = max (x + width - 1) (x' + width' - 1) - x'' + 1
and height'' = max (y + height - 1) (y' + height' - 1) - y'' + 1 in
x'', y'', width'', height''
in
Graphics.draw_image newimg x y;
let workimg = Graphics.get_image wx wy wwidth wheight in
Graphics.draw_image orgimg x y;
do_on_screen (Graphics.draw_image workimg wx) wy;
prev_geom := Some (x, y, width, height)
;;
(* Moving slides or part of slides on the screen,
as specified by the transition method. *)
let sleep = ref (fun _ -> false);;
let current_transition = ref TransNone;;
let slide delay steps from =
(* against full screen *)
let w = Graphics.size_x () and h = Graphics.size_y () in
let img = Graphics.get_image 0 0 w h in
try
for i = steps - 1 downto 1 do
if delay <> 0.0 then if !sleep delay then raise Exit;
let px, py =
match from with
| DirLeft -> -w / steps * i, 0
| DirBottom -> 0, -h / steps * i
| DirTop -> 0, h / steps * i
| DirTopLeft -> -w / steps * i, h / steps * i
| DirTopRight -> w / steps * i, h / steps * i
| DirBottomRight -> w / steps * i, -h / steps * i
| DirBottomLeft -> -w / steps * i, -h / steps * i
| DirRight | _ -> w / steps * i, 0
in
Graphics.draw_image img px py;
done
with
| Exit -> ()
;;
let wipe delay steps from (w, h) (x, y) =
(* bit naive implementation (=inefficient) *)
try
for i = steps - 1 downto 1 do
if !sleep delay then raise Exit;
let px, py, w, h =
match from with
| DirLeft -> -w / steps * i, 0, w, h
| DirBottom -> 0, -h / steps * i, w, h
| DirTop -> 0, h / steps * i, w, h
| DirTopLeft -> -w / steps * i, h / steps * i, w, h
| DirTopRight -> w / steps * i, h / steps * i, w, h
| DirBottomRight -> w / steps * i, -h / steps * i, w, h
| DirBottomLeft -> -w / steps * i, -h / steps * i, w, h
| DirCenter ->
let j = steps - i in
w / 2 - w / (steps * 2) * j,
h / 2 - h / (steps * 2) * j,
w / steps * j, h / steps * j
| DirRight | _ -> w / steps * i, 0, w, h
in
if w = 0 || h = 0 then () else
let img = Graphics.get_image (px + x) (py + y) w h in
Graphics.draw_image img (px + x) (py + y);
done
with
| Exit -> ()
;;
let block delay steps from (w, h) (x, y) =
let rec find_division dx dy =
if dx * dy > steps then dx, dy else
(* try to add dx 1 *)
let dx1 = dx + 1 in
let w_dx1 = w / dx1 in
let dy1 = if w_dx1 = 0 then 100000 else h / (w / dx1) + 1 in
(* try to add dy 1 *)
let dy2 = dy + 1 in
let h_dy2 = h / dy2 in
let dx2 = if h_dy2 = 0 then 100000 else w / (h / dy2) + 1 in
if dx1 * dy1 < dx2 * dy2 then find_division dx1 dy1
else find_division dx2 dy2
in
let dx, dy =
let dx, dy = find_division 1 1 in
let dx = if dx = 0 then 1 else dx
and dy = if dy = 0 then 1 else dy in
if dx * dy > w * h then w, h else dx, dy
in
let bw = w / dx + (if w mod dx = 0 then 0 else 1) in
let bh = h / dy + (if h mod dy = 0 then 0 else 1) in
let img = Graphics.create_image bw bh in
let swap order a b =
let tmp = order.(a) in
order.(a) <- order.(b);
order.(b) <- tmp
in
let order =
let priority =
match from with
| DirLeft -> fun x y -> x
| DirRight -> fun x y -> -x
| DirBottom -> fun x y -> y
| DirTop -> fun x y -> -y
| DirTopLeft -> fun x y -> x - y
| DirTopRight -> fun x y -> -x - y
| DirBottomLeft -> fun x y -> x + y
| DirBottomRight -> fun x y -> -x + y
| DirCenter -> fun x y -> abs (x - dx / 2) + abs (y - dy / 2)
| DirNone -> fun x y -> Random.int (dx * dy)
in
let order = Array.init (dx * dy) (fun i ->
let x = i mod dx and y = i / dx in
priority x y, (x, y) )
in
Array.sort compare order;
for i = 0 to dx * dy - 1 do
let j = i + Random.int (dx * dy / 20) in
if j < 0 || j >= dx * dy then ()
else swap order i j
done;
order
in
try
for i = 0 to dx * dy - 1 do
if !sleep delay then raise Exit;
let _, (bx, by) = order.(i) in
Graphics.blit_image img (bx * bw + x) (by * bh + y);
Graphics.draw_image img (bx * bw + x) (by * bh + y);
done
with Exit -> ()
;;
(* Moving images along a general user's specified path. *)
(* Collection of predefined path generators wired in. *)
let get_genpath = function
| "spiral" ->
(fun steps (sx, sy, ss, sr) (tx, ty, ts, tr) i ->
failwith "Spiral not yet implemented")
| "line" ->
(fun steps (sx, sy, ss, sr) (tx, ty, ts, tr) ->
let stepx = (tx -. sx) /. float steps
and stepy = (ty -. sy) /. float steps in
let steps = (ts -. ss) /. float steps
and stepr = (tr -. sr) /. float steps in
fun i ->
let x, y =
sx +. float i *. stepx,
sy +. float i *. stepy in
let s, r =
ss +. float i *. steps,
sr +. float i *. stepr in
(x, y, s, r))
| s -> failwith ("Unknown path " ^ s)
;;
(* Scaling sprites. *)
let rescale_grimage img w h nw nh =
if nw = w && nh = h then img else
let cimg = Graphic_image.image_of img in
Graphic_image.of_image (Images.Rgb24 (Rgb24.resize None cimg nw nh))
;;
(* Rendering function for sprites along a path *)
let render newimg w h
(nextx, nexty, nextscale, nextrot) =
let nw = Misc.round (float w *. nextscale)
and nh = Misc.round (float h *. nextscale) in
let newimg = rescale_grimage newimg w h nw nh in
draw_sprite newimg
(Misc.round nextx) (Misc.round nexty)
nw nh
;;
(* Moving image img along path generated by genpath. *)
let move_along_path newimg w h delay steps genpath start stop =
let genpath = get_genpath genpath steps start stop in
let rec loop prev i =
if i < steps then begin
if !sleep delay then raise Exit;
let next = genpath i in
render newimg w h next;
loop next (i + 1) end in
try loop start 0 with
| Exit -> ()
;;
let path delay steps genpath start stop =
(* against full screen *)
let w = Graphics.size_x () and h = Graphics.size_y () in
let newimg = Graphics.get_image 0 0 w h in
move_along_path newimg w h delay steps genpath start stop;;
let get_steps default = function Some x -> x | None -> default;;
let pathelem_inst (optx, opty, opts, optr) (x, y, s, r) =
let l =
List.map
(function
| Some v, _ -> v
| None, v -> v)
(List.combine [optx; opty; opts; optr] [x; y; s; r]) in
match l with
| [actx; acty; acts; actr] -> (actx, acty, acts, actr)
| _ -> assert false
;;
let synchronize_transition () =
if !current_transition <> TransNone then
let w = Graphics.size_x () and h = Graphics.size_y () in
do_on_screen (fun () ->
match !current_transition with
| TransSlide (steps, from) ->
slide 0.0 (get_steps 20 steps) from
| TransWipe (steps, from) ->
wipe 0.0 (get_steps 20 steps) from (w, h) (0, 0)
| TransBlock (steps, from) ->
block 0.0 (get_steps 5000 steps) from (w, h) (0, 0)
| TransPath (steps, genpath, start, stop) ->
path 0.0 (get_steps 20 steps) genpath
(pathelem_inst start (float w, float h, 1.0, 0.0))
(pathelem_inst stop (0.0, 0.0, 1.0, 0.0))
| TransNone -> assert false
) ()
;;
let string_of_transmode = function
| TransNone -> "none"
| TransSlide _ -> "slide"
| TransBlock _ -> "block"
| TransWipe _ -> "wipe"
| TransPath _ -> "path"
;;
(* Argument oldimg will be useful to transitions with alpha blending,
if we add them in the future. *)
let box_transition trans oldimg newimg x y width height =
let screen_w = Graphics.size_x () and screen_h = Graphics.size_y () in
init_sprite ();
match trans with
| TransNone -> ()
| TransSlide (steps, from) ->
let steps = get_steps 20 steps in
let calc_new_steps_and_speed len =
let steps = if steps <= 0 then 1 else steps in
let speed = max (len / steps) 1 in
let newsteps = len / speed + 1 in
newsteps, speed
in
let f, newsteps =
match from with
| DirRight ->
let len = screen_w - x + width - 1 in
let newsteps, speed = calc_new_steps_and_speed len in
(fun i ->
draw_sprite newimg (x + i * speed) y width height), newsteps
| DirLeft ->
let len = x in
let newsteps, speed = calc_new_steps_and_speed len in
(fun i ->
draw_sprite newimg (x - i * speed) y width height), newsteps
| DirTop ->
let len = screen_h - y + height - 1 in
let newsteps, speed = calc_new_steps_and_speed len in
(fun i ->
draw_sprite newimg x (y + i * speed) width height), newsteps
| DirBottom | _ ->
let len = y in
let newsteps, speed = calc_new_steps_and_speed len in
(fun i ->
draw_sprite newimg x (y - i * speed) width height), newsteps
in
begin try
for i = newsteps - 1 downto 1 do
if !sleep 0.01 then raise Exit
else f i
done
with
| Exit -> ()
end
| TransPath (steps, genpath, start, stop) ->
let steps = get_steps 50 steps in
do_on_screen (fun stop ->
move_along_path newimg width height 0.01 steps genpath
(pathelem_inst start (float x, float y, 1.0, 0.0))
(pathelem_inst stop (float x, float y, 1.0, 0.0))
) stop
| TransBlock (step, from) ->
let step = get_steps 50 step in
do_on_screen (fun () ->
block 0.01 step from (width, height) (x, y)) ()
| TransWipe (step, from) ->
let step = get_steps 50 step in
do_on_screen (fun () ->
wipe 0.01 step from (width, height) (x, y)) ()
;;
let saved_transbox = ref None;;
let transbox_save x y width height =
let x = x and y = y - 1 and width = width + 1 and height = height + 2 in
let img = Graphics.get_image x y width height in
saved_transbox := Some (img, x, y, width, height)
;;
let transbox_go trans =
begin match !saved_transbox with
| Some (oldimg, x, y, width, height) ->
let newimg = Graphics.get_image x y width height in
box_transition trans oldimg newimg x y width height
| None -> assert false
(* ??? forgot to call transbox_save before ??? *)
(* ??? Seems to be room for simplification there: transbox_save should not
be called from within tex but as the first action of trans_go ??? *)
end;
saved_transbox := None;
;;
|