v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Groups Pages
video.h
1 /* -*- mode: C; c-basic-offset: 4; intent-tabs-mode: nil -*-
2  *
3  * This file is part of the public interface to the Sifteo SDK.
4  * Copyright <c> 2012 Sifteo, Inc. All rights reserved.
5  */
6 
7 #pragma once
8 #ifdef NOT_USERSPACE
9 # error This is a userspace-only header, not allowed by the current build.
10 #endif
11 
12 #include <sifteo/abi.h>
13 #include <sifteo/cube.h>
14 #include <sifteo/math.h>
15 #include <sifteo/video/color.h>
16 #include <sifteo/video/sprite.h>
17 #include <sifteo/video/framebuffer.h>
18 #include <sifteo/video/bg0rom.h>
19 #include <sifteo/video/bg0.h>
20 #include <sifteo/video/bg1.h>
21 #include <sifteo/video/bg2.h>
22 #include <sifteo/video/tilebuffer.h>
23 
24 namespace Sifteo {
25 
34 static const unsigned LCD_width = 128;
35 static const unsigned LCD_height = 128;
36 static const unsigned TILE = 8;
37 
39 static const Int2 LCD_size = { LCD_width, LCD_height };
40 
42 static const Int2 LCD_center = { LCD_width / 2, LCD_height / 2 };
43 
44 
60 enum VideoMode {
61  POWERDOWN_MODE = _SYS_VM_POWERDOWN,
62  BG0_ROM = _SYS_VM_BG0_ROM,
63  SOLID_MODE = _SYS_VM_SOLID,
64  FB32 = _SYS_VM_FB32,
65  FB64 = _SYS_VM_FB64,
66  FB128 = _SYS_VM_FB128,
67  BG0 = _SYS_VM_BG0,
68  BG0_BG1 = _SYS_VM_BG0_BG1,
69  BG0_SPR_BG1 = _SYS_VM_BG0_SPR_BG1,
70  BG2 = _SYS_VM_BG2,
71  STAMP = _SYS_VM_STAMP,
72 };
73 
74 
84 enum Rotation {
85  ROT_NORMAL = 0,
86  ROT_LEFT_90_MIRROR = _SYS_VF_XY_SWAP,
87  ROT_MIRROR = _SYS_VF_X_FLIP,
88  ROT_LEFT_90 = _SYS_VF_XY_SWAP | _SYS_VF_Y_FLIP,
89  ROT_180_MIRROR = _SYS_VF_Y_FLIP,
90  ROT_RIGHT_90 = _SYS_VF_XY_SWAP | _SYS_VF_X_FLIP,
91  ROT_180 = _SYS_VF_X_FLIP | _SYS_VF_Y_FLIP,
92  ROT_RIGHT_90_MIRROR = _SYS_VF_XY_SWAP | _SYS_VF_X_FLIP | _SYS_VF_Y_FLIP
93 };
94 
95 
126 struct VideoBuffer {
128  union {
129  _SYSAttachedVideoBuffer sys;
140  };
141 
142  // Implicit conversions
143  operator _SYSVideoBuffer* () { return &sys.vbuf; }
144  operator const _SYSVideoBuffer* () const { return &sys.vbuf; }
145  operator _SYSAttachedVideoBuffer* () { return &sys; }
146  operator const _SYSAttachedVideoBuffer* () const { return &sys; }
147 
155  operator _SYSCubeID () const {
156  return sys.cube;
157  }
158 
162  CubeID cube() const {
163  return sys.cube;
164  }
165 
182  void setWindow(uint8_t firstLine, uint8_t numLines) {
183  poke(offsetof(_SYSVideoRAM, first_line) / 2, firstLine | (numLines << 8));
184  }
185 
190  setWindow(0, LCD_height);
191  }
192 
196  void setWindowFirstLine(uint8_t firstLine) {
197  pokeb(offsetof(_SYSVideoRAM, first_line), firstLine);
198  }
199 
203  void setWindowNumLines(uint8_t numLines) {
204  pokeb(offsetof(_SYSVideoRAM, num_lines), numLines);
205  }
206 
211  uint8_t windowFirstLine() const {
212  return peekb(offsetof(_SYSVideoRAM, first_line));
213  }
214 
219  uint8_t windowNumLines() const {
220  return peekb(offsetof(_SYSVideoRAM, num_lines));
221  }
222 
227  const uint8_t mask = _SYS_VF_XY_SWAP | _SYS_VF_X_FLIP | _SYS_VF_Y_FLIP;
228  uint8_t flags = peekb(offsetof(_SYSVideoRAM, flags));
229 
230  // Must do this atomically; the asynchronous paint controller can
231  // modify other bits within this flags byte.
232  xorb(offsetof(_SYSVideoRAM, flags), (r ^ flags) & mask);
233  }
234 
238  Rotation rotation() const {
239  const uint8_t mask = _SYS_VF_XY_SWAP | _SYS_VF_X_FLIP | _SYS_VF_Y_FLIP;
240  uint8_t flags = peekb(offsetof(_SYSVideoRAM, flags));
241  return Rotation(mask & flags);
242  }
243 
248  Side orientation() const {
249  switch (rotation()) {
250  case ROT_NORMAL: return TOP;
251  case ROT_LEFT_90: return LEFT;
252  case ROT_180: return BOTTOM;
253  case ROT_RIGHT_90: return RIGHT;
254  default: return NO_SIDE;
255  }
256  }
257 
264  void setOrientation(Side topSide) {
265  // Tiny lookup table in a uint32
266  const uint32_t sideToRotation =
267  (ROT_NORMAL << 0) |
268  (ROT_LEFT_90 << 8) |
269  (ROT_180 << 16) |
270  (ROT_RIGHT_90 << 24) ;
271 
272  ASSERT(topSide >= 0 && topSide < 4);
273  uint8_t r = sideToRotation >> (topSide * 8);
274  setRotation(Rotation(r));
275  }
276 
290  void orientTo(const Neighborhood &thisN, const VideoBuffer &src, const Neighborhood &srcN) {
291  int srcSide = srcN.sideOf(cube());
292  int dstSide = thisN.sideOf(src.cube());
293  if(srcSide != NO_SIDE && dstSide != NO_SIDE) {
294  setOrientation(Side(umod(2 + dstSide - srcSide + src.orientation(), NUM_SIDES)));
295  }
296 
297  }
298 
308  void orientTo(const VideoBuffer &src) {
309  orientTo(Neighborhood(cube()), src, Neighborhood(src.cube()));
310  }
311 
316  static Side physicalToVirtual(Side side, Side rot) {
317  if (side == NO_SIDE) { return NO_SIDE; }
318  ASSERT(side >= 0 && side < 4 && rot != NO_SIDE);
319  return Side(umod(side - rot, NUM_SIDES));
320  }
321 
326  static Side virtualToPhysical(Side side, Side rot) {
327  if (side == NO_SIDE) { return NO_SIDE; }
328  ASSERT(side >= 0 && side < 4 && rot != NO_SIDE);
329  return Side(umod(side + rot, NUM_SIDES));
330  }
331 
337  return physicalToVirtual(side, orientation());
338  }
339 
345  return virtualToPhysical(side, orientation());
346  }
347 
359  Neighborhood result;
360  result.sys.sides[0] = nb.sys.sides[virtualToPhysical(Side(0), rot)];
361  result.sys.sides[1] = nb.sys.sides[virtualToPhysical(Side(1), rot)];
362  result.sys.sides[2] = nb.sys.sides[virtualToPhysical(Side(2), rot)];
363  result.sys.sides[3] = nb.sys.sides[virtualToPhysical(Side(3), rot)];
364  return result;
365  }
366 
378  Neighborhood result;
379  result.sys.sides[0] = nb.sys.sides[physicalToVirtual(Side(0), rot)];
380  result.sys.sides[1] = nb.sys.sides[physicalToVirtual(Side(1), rot)];
381  result.sys.sides[2] = nb.sys.sides[physicalToVirtual(Side(2), rot)];
382  result.sys.sides[3] = nb.sys.sides[physicalToVirtual(Side(3), rot)];
383  return result;
384  }
385 
397  return physicalToVirtual(nb, orientation());
398  }
399 
411  return virtualToPhysical(nb, orientation());
412  }
413 
423  return Neighborhood(cube());
424  }
425 
435  }
436 
445  return cube().accel();
446  }
447 
454  Byte3 virtualAccel() const {
455  return cube().accel().zRotateI(orientation());
456  }
457 
467  void setMode(VideoMode m) {
468  pokeb(offsetof(_SYSVideoRAM, mode), m);
469  }
470 
474  VideoMode mode() const {
475  return VideoMode(peekb(offsetof(_SYSVideoRAM, mode)));
476  }
477 
485  void erase() {
486  _SYS_vbuf_fill(*this, 0, 0, _SYS_VA_FIRST_LINE / 2);
487  }
488 
508  void initMode(VideoMode m, unsigned firstLine = 0, unsigned numLines = LCD_height) {
509  _SYS_finish();
510  erase();
511  setWindow(firstLine, numLines);
512  setRotation(ROT_NORMAL);
513  setMode(m);
514  }
515 
537  void attach(_SYSCubeID id) {
538  _SYS_finish();
539  sys.cube = id;
540  _SYS_vbuf_init(*this);
541  _SYS_setVideoBuffer(*this, *this);
542  }
543 
554  void lock(uint16_t addr) {
555  _SYS_vbuf_lock(*this, addr);
556  }
557 
565  void unlock() {
566  _SYS_vbuf_unlock(*this);
567  }
568 
576  void touch() {
577  lock(_SYS_VA_FLAGS);
578  }
579 
587  void poke(uint16_t addr, uint16_t word) {
588  _SYS_vbuf_poke(*this, addr, word);
589  }
590 
595  void pokeb(uint16_t addr, uint8_t byte) {
596  _SYS_vbuf_pokeb(*this, addr, byte);
597  }
598 
602  void pokei(uint16_t addr, uint16_t index) {
603  _SYS_vbuf_poke(*this, addr, _SYS_TILE77(index));
604  }
605 
610  void xorb(uint16_t addr, uint8_t byte) {
611  _SYS_vbuf_xorb(*this, addr, byte);
612  }
613 
617  uint16_t peek(uint16_t addr) const {
618  return _SYS_vbuf_peek(*this, addr);
619  }
620 
624  uint8_t peekb(uint16_t addr) const {
625  return _SYS_vbuf_peekb(*this, addr);
626  }
627 };
628 
633 }; // namespace Sifteo