Browse Source

Added documentation downloaded from Lameguy64

master
Nico de Poel 4 years ago
parent
commit
a6cfcba95f
  1. 796
      Docs/Chapter 1.1 Setting up Graphics and Hello World.htm
  2. 474
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/analytics.js
  3. 500
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/banner-styles.css
  4. 147
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/bufferlayout.svg
  5. 3
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/bundle-playback.js
  6. 286
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/gpudiagram.svg
  7. 116
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/iconochive.css
  8. 70
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/style.css
  9. 261
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/vram-layout.svg
  10. 21
      Docs/Chapter 1.1 Setting up Graphics and Hello World_files/wombat.js
  11. 413
      Docs/Chapter 1.2 Drawing Graphics.htm
  12. 474
      Docs/Chapter 1.2 Drawing Graphics_files/analytics.js
  13. 500
      Docs/Chapter 1.2 Drawing Graphics_files/banner-styles.css
  14. 3
      Docs/Chapter 1.2 Drawing Graphics_files/bundle-playback.js
  15. 116
      Docs/Chapter 1.2 Drawing Graphics_files/iconochive.css
  16. 876
      Docs/Chapter 1.2 Drawing Graphics_files/ordertable-buffercompare.svg
  17. 705
      Docs/Chapter 1.2 Drawing Graphics_files/ordertable-multiprims.svg
  18. 657
      Docs/Chapter 1.2 Drawing Graphics_files/ordertable-primitive.svg
  19. 633
      Docs/Chapter 1.2 Drawing Graphics_files/ordertable.svg
  20. 350
      Docs/Chapter 1.2 Drawing Graphics_files/primstruct.svg
  21. 70
      Docs/Chapter 1.2 Drawing Graphics_files/style.css
  22. 21
      Docs/Chapter 1.2 Drawing Graphics_files/wombat.js
  23. 919
      Docs/Chapter 1.3 Textures, TPages and CLUTs.htm
  24. 705
      Docs/Chapter 1.3 Textures, TPages and CLUTs_files/ordertable-multiprims.svg
  25. 268
      Docs/Chapter 1.3 Textures, TPages and CLUTs_files/page-texcoord-relation.svg
  26. 49
      Docs/Chapter 1.3 Textures, TPages and CLUTs_files/style.css
  27. 313
      Docs/Chapter 1.3 Textures, TPages and CLUTs_files/vram-texture-coordinates.svg
  28. 192
      Docs/Chapter 1.3 Textures, TPages and CLUTs_files/vram-texture-pages.svg
  29. 672
      Docs/Chapter 1.4 Controllers.htm
  30. 474
      Docs/Chapter 1.4 Controllers_files/analytics.js
  31. 500
      Docs/Chapter 1.4 Controllers_files/banner-styles.css
  32. 3
      Docs/Chapter 1.4 Controllers_files/bundle-playback.js
  33. 116
      Docs/Chapter 1.4 Controllers_files/iconochive.css
  34. 70
      Docs/Chapter 1.4 Controllers_files/style.css
  35. 21
      Docs/Chapter 1.4 Controllers_files/wombat.js
  36. 826
      Docs/Chapter 1.5 Fixed point Math.htm
  37. 49
      Docs/Chapter 1.5 Fixed point Math_files/style.css
  38. 807
      Docs/Chapter 1.6 Using the CD-ROM.htm
  39. 49
      Docs/Chapter 1.6 Using the CD-ROM_files/style.css
  40. 508
      Docs/Chapter 2.2 Reading a file from CD-ROM.htm
  41. 474
      Docs/Chapter 2.2 Reading a file from CD-ROM_files/analytics.js
  42. 500
      Docs/Chapter 2.2 Reading a file from CD-ROM_files/banner-styles.css
  43. 3
      Docs/Chapter 2.2 Reading a file from CD-ROM_files/bundle-playback.js
  44. 116
      Docs/Chapter 2.2 Reading a file from CD-ROM_files/iconochive.css
  45. 70
      Docs/Chapter 2.2 Reading a file from CD-ROM_files/style.css
  46. 21
      Docs/Chapter 2.2 Reading a file from CD-ROM_files/wombat.js
  47. BIN
      Docs/LibPSn00b Reference.pdf

796
Docs/Chapter 1.1 Setting up Graphics and Hello World.htm

@ -0,0 +1,796 @@
<html><head><script src="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/analytics.js" type="text/javascript"></script>
<script type="text/javascript">window.addEventListener('DOMContentLoaded',function(){var v=archive_analytics.values;v.service='wb';v.server_name='wwwb-app211.us.archive.org';v.server_ms=363;archive_analytics.send_pageview({});});</script>
<script type="text/javascript" src="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/bundle-playback.js" charset="utf-8"></script>
<script type="text/javascript" src="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/wombat.js" charset="utf-8"></script>
<script type="text/javascript">
__wm.init("http://web.archive.org/web");
__wm.wombat("http://lameguy64.net/tutorials/pstutorials/chapter1/1-display.html","20220827033533","http://web.archive.org/","web","/_static/",
"1661571333");
</script>
<link rel="stylesheet" type="text/css" href="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/banner-styles.css">
<link rel="stylesheet" type="text/css" href="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/iconochive.css">
<!-- End Wayback Rewrite JS Include -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/style.css">
<title>Chapter 1.1: Setting up Graphics and Hello World</title><meta http-equiv="Content-Type" content="text/html; charset=windows-1252"></head>
<body><!-- BEGIN WAYBACK TOOLBAR INSERT -->
<style type="text/css">
body {
margin-top:0 !important;
padding-top:0 !important;
/*min-width:800px !important;*/
}
</style>
<script>__wm.rw(0);</script>
<div id="wm-ipp-base" style="display: block; direction: ltr; height: 1px;" lang="en">
</div><div id="wm-ipp-print">The Wayback Machine -
http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter1/1-display.html</div>
<script type="text/javascript">//<![CDATA[
__wm.bt(675,27,25,2,"web","http://lameguy64.net/tutorials/pstutorials/chapter1/1-display.html","20220827033533",1996,"/_static/",["/_static/css/banner-styles.css?v=fantwOh2","/_static/css/iconochive.css?v=qtvMKcIJ"], false);
__wm.rw(1);
//]]></script>
<!-- END WAYBACK TOOLBAR INSERT -->
<h1>1.1. Setting up Graphics and Hello World</h1>
<p>
This chapter teaches the basics of initializing and setting up the GPU of the
PSX. Areas covered in this chapter include the GPU, VRAM and the concept of
display and drawing environments which are essential for better understanding
how the GPU works when programming for the PSX.
</p>
<p>
This tutorial series does not and will not cover graphics programming using the
LIBGS library which is a high level graphics library that adds about 100KB
worth of overhead to your project (remember that the PSX only has 2MB of RAM)
and hides many of the inner workings of the GPU, making it difficult to
understand how to use the GPU directly and would often get in the way when
trying to write your own graphics routines... While it may sound elitist
discouraging the use of LIBGS as it provides facilities for rendering 3D models
easily, it is better to learn how to work with LIBGPU (or PSXGPU in PSn00bSDK)
in the long term as the knowledge gained from learning how to use it directly
will become very important in the future for either better performance, or to
accomplish special graphical effects.
</p>
<p><b>Tutorial compatible with PSn00bSDK:</b>Yes</p>
<h2>Chapter Index</h2>
<ul>
<li><a href="#whystart">Why Start with Graphics?</a></li>
<li><a href="#gpusummary">Brief Summary of the GPU</a></li>
<li><a href="#hellostart">Writing the Hello World Program</a></li>
<li><a href="#gpusetup">Setting up Graphics</a></li>
<li><a href="#hellodisplay">Displaying the Hello World</a></li>
<li><a href="#samplecode">Final Sample Code</a></li>
<li><a href="#result">Result</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
<h2 id="whystart">Why Start with Graphics?</h2>
<p>
This tutorial series begins with graphics programming as displaying a hello
world message requires a bit of graphics programming, as neither the official
SDK or PSn00bSDK provide a framebuffer text console for displaying text largely
due to the way how the hardware works. But both provide a means of basic text
drawing functions intended for debugging purposes which will be demonstrated
for this chapter.
</p>
<p>
Besides, most of the satisfaction gained when learning to develop for a new
platform comes from seeing the result displayed on the television screen by the
console you're learning to develop for and you're going need to learn graphics
programming anyway to really be able to do anything interesting with the PSX.
It is a <b>video</b> game console afterall.
</p>
<h2 id="gpusummary">Brief Summary of the GPU</h2>
<p>
The GPU, as the name suggests, is the graphics processor responsible for doing
the graphics rendering work for both 2D and 3D visuals. The block diagram shown
below illustrates the relevant components that make up the entirerity of the
PSX's graphics subsystem, including the MDEC and GTE hardware responsible for
video playback and 3D graphics capabilities respectively.
</p>
<img src="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/gpudiagram.svg">
<ul>
<li>1MB of VRAM with 16-bit data bus.</li>
<li>2KB of texture cache.</li>
<li>Supports non-interlaced, low resolution and interlaced, high resolution
video modes.</li>
<li>16-bit color rendering with optional dithering.</li>
<li>Draws rectangles, sprites, lines, polylines, flat, shaded and texture
mapped polygon primitives.</li>
<li>Estimated 300,000 flat and gouraud shaded polygons per second.</li>
<li>Estimated 150,000 texture mapped polygons per second.</li>
</ul>
<h3>The GPU is not 3D</h3>
<p>
A worrying amount often believed that the PSX's GPU is capable of rendering 3D
polygons. While it may seem to be the case to the uneducated, the GPU is in
fact only capable of drawing primitives in 2D space. Therefore, the GPU is
incapable of perspective correct texture mapping which results in affine
texture distortion and the occasional buggy near clipping seen in a lot of 3D
PSX games. It was common for games to minimize the distortion by subdividing
large polygons into smaller polygons with perspective correct subdivision.
</p>
<p>
The bulk of the 3D processing is instead done on the CPU which features a
co-processor suited for such tasks known as the GTE or Geometry Transform
Engine. The GTE is effectively an all integer math co-processor that provides
matrix multiplication, vector transformations and projection operations at high
speed which the CPU alone couldn't do at reasonable speed. Software would then
assemble primitive packets using results from the GTE which are then sent to
the GPU as a linked list via high speed DMA transfer for the GPU to draw said
primitives.
</p>
<p>
The GTE will not be covered in this chapter as it is not required for simple
2D graphics programming. Whilst in the topic of the GTE, a very important
issue must be taken care of and that is the GTE is <b>NOT</b> a Geometry
<i>Transfer</i> Engine. An equally concerning amount belive that the GTE
stands for Geometry Transfer Engine and not a Transform Engine when in fact,
the GTE only does math calculations and is not capable of doing any
<i>"transfer"</i> operations whatsoever. Also, the GTE can only be accessed
by the CPU through standard co-processor related instructions. Just wanted to
clarify this before going any further in learning how to program for the PSX
as this bothers me to no end. Suppose it can be used to identify if one is a
real PSX programmer or not.
</p>
<h3>Only 16-bit Color Rendering</h3>
<p>
Some often mistake that the PSX renders graphics in 24-bit color depth. Whilst
the GPU is capable of 24-bit true color output, it cannot draw primitives in
24-bit color. So the 24-bit color mode is only really useful for MDEC video
sequences or static images in 24-bit color.
</p>
<p>
The GPU can only draw at 16-bit color depth in a RGB5I1 pixel format (five bits
per RGB component plus one mask bit used as a mask for semi-transparency
effects). This aligns perfectly with the 16-bit data bus of the VRAM.
</p>
<h3>The VRAM</h3>
<p>
The GPU features it's own 1MB of VRAM. If you look back at the block diagram
shown earlier you'll see that the VRAM is connected to the GPU and is not
connected the system bus at all. This means the VRAM is not memory mapped and
the CPU cannot access it directly. Instead, VRAM access can only be done
through the GPU. Fortunately, transfers are done via high speed DMA.
</p>
<p>
Naturally, the GPU uses the VRAM for storing framebuffers and texture images.
The most interesting aspect about the VRAM is how the GPU treats it like a
1024x512 16-bit image, with areas of VRAM addressed by (X,Y) coordinates
instead of a linear memory address range. Display and drawing framebuffers as
well as texture images reside as rectangular images in the VRAM. The following
illustrates a typical VRAM layout for framebuffers and texture images in PSX
games.
</p>
<img src="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/vram-layout.svg">
<h3>Primitive Packets</h3>
<p>
The GPU is instructed through the use of primitive packets, which are small
bits of formatted data that make up a GPU command which are sent to the GPU
via DMA for drawing. The primitive packets not only specify the type of
primitive but also the color, semi-transparency flags, (X,Y) coordinates,
texture coordinates, color look-up table to use and so forth. Think of them
like arguments for a function call.
</p>
<p>
The number of arguments a primitive packet requires depends on the type of
primitive. The simplest primitives such as a texture page primitive only takes
one argument while the most sophisticated primitive; a texture mapped, gouraud
shaded, 4-point polygon takes as many as 14 arguments. This also means the
size of the primitive varies, with the texture page primitive being only a
word in size while a 4-point, texture mapped and gouraud shaded polygon is
12 words long on top of the tag word present at the start of all primitives.
</p>
<p>
Further details about primitive packets will be covered in a future chapter.
</p>
<h3>Framebuffers</h3>
<p>
Framebuffers for graphics display and drawing reside in VRAM as rectangular
areas defined in (X,Y) coordinates. The size of the display area is based on
the video mode (ie. the display area is 320x240 pixels when running in
320x240 mode). On the other hand, the size for the drawing area can be of any
arbitrary size which may be used to render texture images for accomplishing
certain render to texture based visual effects. Normally, the size of the
drawing area should typically be equal to the display area.
</p>
<p>
The display and drawing areas are defined as an environment using the
<b>DISPENV</b> and <b>DRAWENV</b> structs. Each struct defines various
parameters that are relevant to their respective environment. The
<b>DISPENV</b> and <b>DRAWENV</b> structs are initialized using
<b>SetDefDispEnv()</b> and <b>SetDefDrawEnv()</b> respectively which defines
the default parameters for each environment, which may be customized later for
your project's requirements. Once the environments have been defined they can
then be applied to the GPU using <b>PutDispEnv()</b> and <b>PutDrawEnv()</b>
to make each environment effective.
</p>
<p>
Learning the display and drawing environments are mandatory for being able to
get any graphical output from the PSX and this will be covered extensively in
this chapter.
</p>
<h2 id="hellostart">Writing the Hello World Program</h2>
<p>
As obligatory as it may sound, a hello world is an effective and simple enough
example to get started with PSX homebrew programming. A hello world program for
the PSX can't be a simple call of printf(), unless you only want to see the
output through a tty which, in all honesty, won't look as interesting as
showing the message on the TV screen or emulator window.
</p>
<p>
The basic run-down of accomplishing a hello world on the PSX is to perform the
following operations:
</p>
<ul>
<li>Initialize the GPU.</li>
<li>Define display and drawing environments.</li>
<li>Initializing the debug font.</li>
<li>Display the hello world text.</li>
</ul>
<p>
Break out your preferred text editor and begin writing the hello world program
as you go along this chapter.
</p>
<h3>Required Headers</h3>
<p>
First, include some necessary headers in your C file. The most important of which is
libgpu.h as it provides various definitions provided by the libgpu library. libgte.h
is required even if you don't plan to use the GTE as libgpu.h depends on some
definitions provided in it.
</p>
<pre>#include &lt;sys/types.h&gt; // This provides typedefs needed by libgte.h and libgpu.h
#include &lt;stdio.h&gt; // Not necessary but include it anyway
#include &lt;libetc.h&gt; // Includes some functions that controls the display
#include &lt;libgte.h&gt; // GTE header, not really used but libgpu.h depends on it
#include &lt;libgpu.h&gt; // GPU library header
</pre>
<p>
If using PSn00bSDK, replace the <b>lib</b> prefix with <b>psx</b> instead. Most
of the definitions between the official SDK and PSn00bSDK are identical, so the
syntax of things shouldn't be much to worry much about.
</p>
<h3>Write the main() Function</h3>
<p>
Like with any C program, you must define a main() function somewhere in your
project. You can omit the argc and argv definitions if desired as they don't
work on the PSX.
</p>
<pre>int main()
{
return 0;
}
</pre>
<p>
A return value cannot be passed to a parent executable as the kernel does not
save the value for the caller to receive it, but is required nonetheless to
keep the compiler from complaining about returning without a value.
</p>
<h2 id="gpusetup">Setting up Graphics</h2>
<p>
The very first thing to do before anything else in your PSX program is to
call <b>ResetGraph()</b>. <b>ResetGraph()</b> not only resets the GPU as the
name suggests, but it also enables interrupts which are mandatory for getting
anything done on the PSX. If <b>ResetGraph()</b> is not called functions that
depend on interrupts such as <b>VSync()</b> and several other things will not
work, and will usually appear as though your program just crashed.
</p>
<pre>// Reset GPU and enable interrupts
ResetGraph(0);
</pre>
<p>
Resetting the GPU also masks out the video output which results in a black
screen, but the console still produces video sync. The video output is enabled
again using <b>SetDispMask()</b>, ideally after a <b>DISPENV</b> has been
defined and applied to the GPU for a smooth transition from a previously
running program (ie. the startup screen). As <b>ResetGraph()</b> does not clear
the contents of VRAM, so whatever was drawn by the previous program still
remains when your program takes over. Clearing the VRAM is generally not
required in most well coded scenarios.
</p>
<h3>Setting up the DISPENV and DRAWENV Environments</h3>
<p>
Start by defining two <b>DISPENV</b> and <b>DRAWENV</b> variables as arrays in
your code. Define an int which will be used for keeping track of things which
will make total sense later on. This value must be set to zero as part of your
graphics initialization code just to make sure the variable starts with a value
of zero.
</p>
<pre>// Define environment pairs and buffer counter
DISPENV disp[2];
DRAWENV draw[2];
int db;
</pre>
<p>
Next is to define the <b>DISPENV</b> pair. Initializing the <b>DISPENV</b>
structure is easiest done using the <b>SetDefDispEnv()</b> function with simple
arguments.
</p>
<b>For NTSC users:</b>
<pre>// Configures the pair of DISPENVs for 320x240 mode (NTSC)
SetDefDispEnv(&amp;disp;[0], 0, 0, 320, 240);
SetDefDispEnv(&amp;disp;[1], 0, 240, 320, 240);
</pre>
<b>For PAL users:</b>
<pre>// Configures the pair of DISPENVs for 320x256 mode (PAL)
SetDefDispEnv(&amp;disp;[0], 0, 0, 320, 256);
SetDefDispEnv(&amp;disp;[1], 0, 256, 320, 256);
// Screen offset to center the picture vertically
disp[0].screen.y = 24;
disp[1].screen.y = disp[0].screen.y;
// Forces PAL video standard
SetVideoMode(MODE_PAL);
</pre>
<p>
This defines both <b>DISPENV</b>s for 320x240 resolution mode (320x256 if you
used the PAL snippet) which is the most commonly used video mode. The first
<b>DISPENV</b> is set with a position of (0,0) while the second <b>DISPENV</b>
is set with a VRAM offset of (0,240). You might be wondering why it has to be
defined that way.
</p>
<p>
Next is to define the <b>DRAWENV</b>s. Much like the <b>DISPENV</b>s you use
<b>SetDefDrawEnv()</b> to initialize the <b>DRAWENV</b> structure with
simple arguments.
</p>
<b>For NTSC users:</b>
<pre>// Configures the pair of DRAWENVs for the DISPENVs
SetDefDrawEnv(&amp;draw;[0], 0, 240, 320, 240);
SetDefDrawEnv(&amp;draw;[1], 0, 0, 320, 240);
</pre>
<b>For PAL users:</b>
<pre>// Configures the pair of DRAWENVs for the DISPENVs
SetDefDrawEnv(&amp;draw;[0], 0, 256, 320, 256);
SetDefDrawEnv(&amp;draw;[1], 0, 0, 320, 256);
</pre>
<p>
Unlike <b>DISPENV</b>, <b>DRAWENV</b> can be of any arbitrary size for the
drawing environment. But generally it should be equal to the size of the
<b>DISPENV</b> defined, so the drawn area will align perfectly with the display
environments. Additionally, you'll want to set some parameters within the
<b>DRAWENV</b> struct to enable background clearing as otherwise you'll get a
hall of mirrors effect. The background clear takes effect as soon as the
<b>DRAWENV</b> is applied to the GPU using <b>PutDrawEnv()</b>.
</p>
<pre>// Specifies the clear color of the DRAWENV
setRGB0(&amp;draw;[0], 63, 0, 127);
setRGB0(&amp;draw;[1], 63, 0, 127);
// Enable background clear
draw[0].isbg = 1;
draw[1].isbg = 1;
</pre>
<p>
Finally, apply the <b>DISPENV</b>/<b>DRAWENV</b> environments to the GPU to
apply the new video mode and drawing environment to achieve a seamless
transition.
</p>
<pre>// Apply environments
PutDispEnv(&amp;disp;[0]);
PutDrawEnv(&amp;draw;[0]);
</pre>
<p>
To keep your code look neat and tidy, you'll want to put all the graphics init
code inside a function, to keep your <b>main()</b> function from looking messy
and will make expanding the program easier in the future.
</p>
<h3>The Concept of Double Buffered Rendering</h3>
<p>
You may have noticed that the <b>DRAWENV</b> pairs are somewhat positioned in
the opposite order as the <b>DISPENV</b> whilst writing the graphics init code
and are probably wondering why this is the case instead of a <b>DRAWENV</b>
directly overlapping a <b>DISPENV</b>. This is how you implement double
buffered rendering on the PSX and is a standard feature to have when writing
real-time graphics code, not just on the PSX but on almost any system with a
framebuffer.
</p>
<p>
If you're not familiar with the concept, you basically need to allocate two
framebuffer areas; one for display and one for drawing. The way you use these
framebuffers is you use one buffer as the display buffer, which is the buffer
the graphics hardware will display on the screen and the other as the drawing
buffer, where all your graphics operations should draw to and is not shown on
the screen. Once drawing is complete the two buffers switch places, the drawing
buffer becomes the display buffer and the display buffer become the drawing
buffer for the next frame to be drawn and the cycle repeats. This basically
guarantees that only completed frames are shown on the screen which yields
seamless graphical animations even during framerate drops when intensive
visuals are being drawn aside from the natural reduction of smoothness.
</p>
<img src="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/bufferlayout.svg">
<p>
Having a <b>DISPENV</b> and a <b>DRAWENV</b> simply overlap one another on the
same area counts as single buffered rendering and whilst you may get away with
it, the amount of things you can draw/process will be severely limited as you'll
get nasty flicker if the drawing/processing does not complete before the v-blank
period ends. So, a double buffered rendering scheme is much preferred.
</p>
<h3>The Display Function</h3>
<p>
Now the last thing that deals with the <b>DISPENV</b> and <b>DRAWENV</b>
environments to write is a so called display function, which is basically
a function that does the all buffer swap stuff in a single call for
convenience. Calling the display function should be done at the end of your
loop as that is usually where all graphics operations have completed
and are ready for drawing or display. For this tutorial, the display function
will be named <h>display()</h>.
</p>
<p>
Before performing a buffer swap, you must first call <b>DrawSync()</b> then
<b>VSync()</b>. As the names suggests these functions waits for the GPU to
complete any drawing operations and waits for the vertical blanking period
respectively. Waiting for <b>DrawSync()</b> is important as it makes sure that
the GPU has completed drawing any primitives as otherwise you may get flicker
or possibly instability. Waiting for <b>VSync()</b> is also important as it
not only caps your program loop to the TV refresh rate (60fps for NTSC, 50
for PAL) but it also prevents screen tearing which will happen if you swap
buffers without waiting for the v-blank period.
</p>
<pre>// Wait for GPU to finish drawing and V-Blank
DrawSync(0);
VSync(0);
</pre>
<p>
Now the next step is to perform the buffer swap. If you remember that variable
named <h>db</h> earlier, this variable will be used as a counter to keep track
of which buffer pair to switch to. Since there are only two <b>DISPENV</b> and
<b>DRAWENV</b> pairs this variable will simply alternate between 1 and 0 on
every call of the display function. This easily achieved using a NOT (!)
operator.
</p>
<pre>// Flip buffer counter
db = !db;
</pre>
<p>
Then apply the environment pair based on the value of <h>db</h> to the GPU.
</p>
<pre>// Apply environments
PutDispEnv(&amp;disp;[db]);
PutDrawEnv(&amp;draw;[db]);
</pre>
<p>
And finally, call <b>SetDispMask()</b> to lift the display mask so you get
picture instead of a black screen, as <b>ResetGraph()</b> masks the display
by default.
</p>
<pre>// Enable display
SetDispMask(1);
</pre>
<h3>Verifying the Code</h3>
<p>
To make sure you're right on track, here's a listing of what the code should
look like.
</p>
<pre>#include &lt;sys/types.h&gt; // This provides typedefs needed by libgte.h and libgpu.h
#include &lt;stdio.h&gt; // Not necessary but include it anyway
#include &lt;libetc.h&gt; // Includes some functions that controls the display
#include &lt;libgte.h&gt; // GTE header, not really used but libgpu.h depends on it
#include &lt;libgpu.h&gt; // GPU library header
// Define environment pairs and buffer counter
DISPENV disp[2];
DRAWENV draw[2];
int db;
void init(void)
{
// Reset GPU and enable interrupts
ResetGraph(0);
// Configures the pair of DISPENVs for 320x240 mode (NTSC)
SetDefDispEnv(&amp;disp;[0], 0, 0, 320, 240);
SetDefDispEnv(&amp;disp;[1], 0, 240, 320, 240);
// Configures the pair of DRAWENVs for the DISPENVs
SetDefDrawEnv(&amp;draw;[0], 0, 240, 320, 240);
SetDefDrawEnv(&amp;draw;[1], 0, 0, 320, 240);
// Specifies the clear color of the DRAWENV
setRGB0(&amp;draw;[0], 63, 0, 127);
setRGB0(&amp;draw;[1], 63, 0, 127);
// Enable background clear
draw[0].isbg = 1;
draw[1].isbg = 1;
// Apply environments
PutDispEnv(&amp;disp;[0]);
PutDrawEnv(&amp;draw;[0]);
// Make sure db starts with zero
db = 0;
}
void display(void)
{
// Wait for GPU to finish drawing and V-Blank
DrawSync(0);
VSync(0);
// Flip buffer counter
db = !db;
// Apply environments
PutDispEnv(&amp;disp;[db]);
PutDrawEnv(&amp;draw;[db]);
// Enable display
SetDispMask(1);
}
int main()
{
// Initialize graphics and stuff
init();
// Main loop
while(1)
{
display();
}
return 0;
}
</pre>
<h3>Compiling and Testing</h3>
<p>Now that you've written a considerable amount of code for the graphics
init and buffer swapping stuff, it should be possible to compile the code
and see an output to check if you're right on track. In the official
PsyQ/Programmers' Tool SDK compiling can be done through <b>ccpsx</b> with
a single command line. <b>ccpsx</b> is actually a front for the C, C++ and
linker that makes using the SDK's toolchain easier.
</p>
<pre>ccpsx -O2 -Xo0x80010000 hello.c -o hello.cpe
</pre>
<p>
If you've worked with C before, you should already know that <h>-O2</h>
specifies the optimization level for the compiler generated code just like
in most other C compilers. The <h>-Xo0x80010000</h> parameter would likely
be unfamiliar to you and this specifies the target address your executable's
program text is going to reside when it is being loaded by the console.
The target address is usually set to 0x80010000 which is the start of user
space memory on the PSX as the first 64KB is reserved by the kernel.
</p>
<p>
The executables <b>ccpsx</b> produces are in CPE format which cannot be
booted from the CD by the PSX and most emulators don't support it. You'll
have to convert the executable into the usable PS-EXE format which can be
done using <b>cpe2x</b>.
</p>
<pre>cpe2x hello.cpe
</pre>
<p>Don't be fooled by the .EXE file extension of a PS-EXE executable file. The
executable files <b>cpe2x</b> produces are neither MS-DOS or Windows
executable programs.
</p>
<p>If using PSn00bSDK. It is more complicated to compile a program from within
the command line alone due to the way how the toolchain is currently set up.
It is much easier to just copy a makefile from one of the examples included
in the SDK and tweak the variables for your project. Then use <b>make</b>
to compile the program and it should produce an ELF file and a PS-EXE file.
</p>
<p>Run the program and you should get a solid blue image.
</p>
<img src="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/1-display.png">
<h2 id="hellodisplay">Displaying the Hello World</h2>
<p>Now that the graphics environment and display routines have been implemented,
the next step is to draw the hello world message. This is easily done by using
the debug font functions <b>FntLoad()</b>, <b>FntOpen()</b> and
<b>FntPrint()</b>. These functions are not suited for general use. Such as in
a game title as it does not support any form of customization and does not
support lowercase letters, but is good enough for testing and debugging
purposes which will be useful later. These functions are provided by libetc,
or psxetc in PSn00bSDK.
</p>
<h3>Setting up the Debug Font</h3>
<p>The first thing to do before the debug font functions can be used is to is
load the font texture onto VRAM using <b>FntLoad()</b>. The font texture can be
placed anywhere in the VRAM area provided it doesn't get overwritten by
display/draw areas, or textures being loaded onto VRAM. For this tutorial, the
font texture will be placed at (960,0).
</p>
<p>Next is to create a text stream using <b>FntOpen()</b> which defines the
area where the text will be drawn at. For this tutorial a text stream of 100
characters is defined to fill the entire screen, with some overscan
compensation to ensure that the text is visible on the TV.
</p>
<pre>// Load the internal font texture
FntLoad(960, 0);
// Create the text stream
FntOpen(0, 8, 320, 224, 0, 100);
</pre>
<p>The font area coordinates are draw-area relative and not VRAM relative, so
there is no need to define another font area for each of the display/draw areas
in the VRAM. The third argument specifies if a black background for the font
area should be drawn. In PSn00bSDK, you can specify 2 for a semi-transparent
black background. If you try to set it to a non-zero value, the background will
turn black because the font area covers the entire screen.
</p>
<p><b>FntOpen()</b> allows defining multiple font areas by saving the return
value to a persistent variable and passing it as the first argument of
<b>FntPrint()</b> and <b>FntFlush()</b>. Up to eight font areas can be defined
at once, but it cannot be closed or redefined later in your program.
</p>
<h3>Printing and Displaying Hello World</h3>
<p><b>FntPrint()</b> prints text to the last defined font area and works more
or less like <b>printf()</b> and you can also use the newline character
sequence <h>\n</h> to move a line of text down. A font handle can be specified
as an optional first argument of <b>FntPrint()</b>, but in PSn00bSDK a handle
from <b>FntOpen()</b> or -1 must be specified as the first argument. This
</p>
<pre>FntPrint("HELLO WORLD!");
FntFlush(-1);
display();
</pre>
<p>Calling <b>FntPrint()</b> alone is not enough to display text to the
current draw area, so <b>FntFlush()</b> needs to be called to actually draw
the characters printed from <b>FntPrint()</b> calls.
</p>
<h2 id="samplecode">Final Sample Code</h2>
<p>Compare your code against this listing to make sure you're right on
track.
</p>
<pre>#include &lt;sys/types.h&gt; // This provides typedefs needed by libgte.h and libgpu.h
#include &lt;stdio.h&gt; // Not necessary but include it anyway
#include &lt;libetc.h&gt; // Includes some functions that controls the display
#include &lt;libgte.h&gt; // GTE header, not really used but libgpu.h depends on it
#include &lt;libgpu.h&gt; // GPU library header
// Define environment pairs and buffer counter
DISPENV disp[2];
DRAWENV draw[2];
int db;
void init(void)
{
// Reset GPU and enable interrupts
ResetGraph(0);
// Configures the pair of DISPENVs for 320x240 mode (NTSC)
SetDefDispEnv(&amp;disp;[0], 0, 0, 320, 240);
SetDefDispEnv(&amp;disp;[1], 0, 240, 320, 240);
// Configures the pair of DRAWENVs for the DISPENVs
SetDefDrawEnv(&amp;draw;[0], 0, 240, 320, 240);
SetDefDrawEnv(&amp;draw;[1], 0, 0, 320, 240);
// Specifies the clear color of the DRAWENV
setRGB0(&amp;draw;[0], 63, 0, 127);
setRGB0(&amp;draw;[1], 63, 0, 127);
// Enable background clear
draw[0].isbg = 1;
draw[1].isbg = 1;
// Apply environments
PutDispEnv(&amp;disp;[0]);
PutDrawEnv(&amp;draw;[0]);
// Make sure db starts with zero
db = 0;
// Load the internal font texture
FntLoad(960, 0);
// Create the text stream
FntOpen(0, 8, 320, 224, 0, 100);
}
void display(void)
{
// Wait for GPU to finish drawing and V-Blank
DrawSync(0);
VSync(0);
// Flip buffer counter
db = !db;
// Apply environments
PutDispEnv(&amp;disp;[db]);
PutDrawEnv(&amp;draw;[db]);
// Enable display
SetDispMask(1);
}
int main()
{
// Initialize graphics and stuff
init();
// Main loop
while(1)
{
FntPrint("HELLO WORLD!");
FntFlush(-1);
display();
}
return 0;
}
</pre>
<h2 id="result">Result</h2>
<p>Run the program on the console or emulator and you should see a
dark purple picture:</p>
<img src="Chapter%201.1%20Setting%20up%20Graphics%20and%20Hello%20World_files/1-hello.png">
<h2 id="conclusion">Conclusion</h2>
<p>This concludes this chapter of Lameguy64's PSX Tutorial series. You should
be very familiar of how framebuffers are handled on the PSX hardware and
should be ready to take on drawing proper graphics primitives.</p>
<p>A few things you may want to experiment with this example yourself:</p>
<ul>
<li>Try ordering the areas side by side.</li>
<li>Go to the VRAM/GPU Viewer in no$psx or press F12 in PSXfin to visually
see the buffers in action. This also works for retail games.</li>
<li>Play around with the clear color values on the <b>DRAWENV</b> environments.
Make sure the color values on both <b>DRAWENV</b> elements are the same
otherwise intense flickering will occur.</li>
</ul>
<p>The next tutorial will cover how to draw graphics with the GPU using
ordering tables and primitive packets.</p>
<hr>
<table class="footer-table" width="100%">
<tbody><tr>
<td width="40%" align="left">Previous</td>
<td width="20%" align="center"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/index.html">Back to Index</a></td>
<td width="40%" align="right"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter1/2-graphics.html">Next</a></td>
</tr>
</tbody></table>
</body></html>
<!--
FILE ARCHIVED ON 03:35:33 Aug 27, 2022 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 15:40:14 Sep 05, 2022.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->
<!--
playback timings (ms):
captures_list: 94.63
exclusion.robots: 0.244
exclusion.robots.policy: 0.234
cdx.remote: 0.081
esindex: 0.011
LoadShardBlock: 61.049 (3)
PetaboxLoader3.datanode: 58.129 (4)
CDXLines.iter: 18.978 (3)
load_resource: 261.231
PetaboxLoader3.resolve: 226.231
-->

474
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/analytics.js

@ -0,0 +1,474 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0
/* eslint-disable no-var, semi, prefer-arrow-callback, prefer-template */
/**
* Collection of methods for sending analytics events to Archive.org's analytics server.
*
* These events are used for internal stats and sent (in anonymized form) to Google Analytics.
*
* @see analytics.md
*
* @type {Object}
*/
window.archive_analytics = (function defineArchiveAnalytics() {
// keep orignal Date object so as not to be affected by wayback's
// hijacking global Date object
var Date = window.Date;
var ARCHIVE_ANALYTICS_VERSION = 2;
var DEFAULT_SERVICE = 'ao_2';
var NO_SAMPLING_SERVICE = 'ao_no_sampling'; // sends every event instead of a percentage
var startTime = new Date();
/**
* @return {Boolean}
*/
function isPerformanceTimingApiSupported() {
return 'performance' in window && 'timing' in window.performance;
}
/**
* Determines how many milliseconds elapsed between the browser starting to parse the DOM and
* the current time.
*
* Uses the Performance API or a fallback value if it's not available.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
*
* @return {Number}
*/
function getLoadTime() {
var start;
if (isPerformanceTimingApiSupported())
start = window.performance.timing.domLoading;
else
start = startTime.getTime();
return new Date().getTime() - start;
}
/**
* Determines how many milliseconds elapsed between the user navigating to the page and
* the current time.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
*
* @return {Number|null} null if the browser doesn't support the Performance API
*/
function getNavToDoneTime() {
if (!isPerformanceTimingApiSupported())
return null;
return new Date().getTime() - window.performance.timing.navigationStart;
}
/**
* Performs an arithmetic calculation on a string with a number and unit, while maintaining
* the unit.
*
* @param {String} original value to modify, with a unit
* @param {Function} doOperation accepts one Number parameter, returns a Number
* @returns {String}
*/
function computeWithUnit(original, doOperation) {
var number = parseFloat(original, 10);
var unit = original.replace(/(\d*\.\d+)|\d+/, '');
return doOperation(number) + unit;
}
/**
* Computes the default font size of the browser.
*
* @returns {String|null} computed font-size with units (typically pixels), null if it cannot be computed
*/
function getDefaultFontSize() {
var fontSizeStr;
if (!('getComputedStyle' in window))
return null;
var style = window.getComputedStyle(document.documentElement);
if (!style)
return null;
fontSizeStr = style.fontSize;
// Don't modify the value if tracking book reader.
if (document.querySelector('#BookReader'))
return fontSizeStr;
return computeWithUnit(fontSizeStr, function reverseBootstrapFontSize(number) {
// Undo the 62.5% size applied in the Bootstrap CSS.
return number * 1.6;
});
}
/**
* Get the URL parameters for a given Location
* @param {Location}
* @return {Object} The URL parameters
*/
function getParams(location) {
if (!location) location = window.location;
var vars;
var i;
var pair;
var params = {};
var query = location.search;
if (!query) return params;
vars = query.substring(1).split('&');
for (i = 0; i < vars.length; i++) {
pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
}
function getMetaProp(name) {
var metaTag = document.querySelector('meta[property=' + name + ']');
return metaTag ? metaTag.getAttribute('content') || null : null;
}
var ArchiveAnalytics = {
/**
* @type {String|null}
*/
service: getMetaProp('service'),
mediaType: getMetaProp('mediatype'),
primaryCollection: getMetaProp('primary_collection'),
/**
* Key-value pairs to send in pageviews (you can read this after a pageview to see what was
* sent).
*
* @type {Object}
*/
values: {},
/**
* Sends an analytics ping, preferably using navigator.sendBeacon()
* @param {Object} values
* @param {Function} [onload_callback] (deprecated) callback to invoke once ping to analytics server is done
* @param {Boolean} [augment_for_ao_site] (deprecated) if true, add some archive.org site-specific values
*/
send_ping: function send_ping(values, onload_callback, augment_for_ao_site) {
if (typeof window.navigator !== 'undefined' && typeof window.navigator.sendBeacon !== 'undefined')
this.send_ping_via_beacon(values);
else
this.send_ping_via_image(values);
},
/**
* Sends a ping via Beacon API
* NOTE: Assumes window.navigator.sendBeacon exists
* @param {Object} values Tracking parameters to pass
*/
send_ping_via_beacon: function send_ping_via_beacon(values) {
var url = this.generate_tracking_url(values || {});
window.navigator.sendBeacon(url);
},
/**
* Sends a ping via Image object
* @param {Object} values Tracking parameters to pass
*/
send_ping_via_image: function send_ping_via_image(values) {
var url = this.generate_tracking_url(values || {});
var loadtime_img = new Image(1, 1);
loadtime_img.src = url;
loadtime_img.alt = '';
},
/**
* Construct complete tracking URL containing payload
* @param {Object} params Tracking parameters to pass
* @return {String} URL to use for tracking call
*/
generate_tracking_url: function generate_tracking_url(params) {
var baseUrl = '//analytics.archive.org/0.gif';
var keys;
var outputParams = params;
var outputParamsArray = [];
outputParams.service = outputParams.service || this.service || DEFAULT_SERVICE;
// Build array of querystring parameters
keys = Object.keys(outputParams);
keys.forEach(function keyIteration(key) {
outputParamsArray.push(encodeURIComponent(key) + '=' + encodeURIComponent(outputParams[key]));
});
outputParamsArray.push('version=' + ARCHIVE_ANALYTICS_VERSION);
outputParamsArray.push('count=' + (keys.length + 2)); // Include `version` and `count` in count
return baseUrl + '?' + outputParamsArray.join('&');
},
/**
* @param {int} page Page number
*/
send_scroll_fetch_event: function send_scroll_fetch_event(page) {
var additionalValues = { ev: page };
var loadTime = getLoadTime();
var navToDoneTime = getNavToDoneTime();
if (loadTime) additionalValues.loadtime = loadTime;
if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
this.send_event('page_action', 'scroll_fetch', location.pathname, additionalValues);
},
send_scroll_fetch_base_event: function send_scroll_fetch_base_event() {
var additionalValues = {};
var loadTime = getLoadTime();
var navToDoneTime = getNavToDoneTime();
if (loadTime) additionalValues.loadtime = loadTime;
if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
this.send_event('page_action', 'scroll_fetch_base', location.pathname, additionalValues);
},
/**
* @param {Object} [options]
* @param {String} [options.mediaType]
* @param {String} [options.mediaLanguage]
* @param {String} [options.page] The path portion of the page URL
*/
send_pageview: function send_pageview(options) {
var settings = options || {};
var defaultFontSize;
var loadTime = getLoadTime();
var mediaType = settings.mediaType;
var primaryCollection = settings.primaryCollection;
var page = settings.page;
var navToDoneTime = getNavToDoneTime();
/**
* @return {String}
*/
function get_locale() {
if (navigator) {
if (navigator.language)
return navigator.language;
else if (navigator.browserLanguage)
return navigator.browserLanguage;
else if (navigator.systemLanguage)
return navigator.systemLanguage;
else if (navigator.userLanguage)
return navigator.userLanguage;
}
return '';
}
defaultFontSize = getDefaultFontSize();
// Set field values
this.values.kind = 'pageview';
this.values.timediff = (new Date().getTimezoneOffset()/60)*(-1); // *timezone* diff from UTC
this.values.locale = get_locale();
this.values.referrer = (document.referrer == '' ? '-' : document.referrer);
if (loadTime)
this.values.loadtime = loadTime;
if (navToDoneTime)
this.values.nav_to_done_ms = navToDoneTime;
if (settings.trackingId) {
this.values.ga_tid = settings.trackingId;
}
/* START CUSTOM DIMENSIONS */
if (defaultFontSize)
this.values.ga_cd1 = defaultFontSize;
if ('devicePixelRatio' in window)
this.values.ga_cd2 = window.devicePixelRatio;
if (mediaType)
this.values.ga_cd3 = mediaType;
if (settings.mediaLanguage) {
this.values.ga_cd4 = settings.mediaLanguage;
}
if (primaryCollection) {
this.values.ga_cd5 = primaryCollection;
}
/* END CUSTOM DIMENSIONS */
if (page)
this.values.page = page;
this.send_ping(this.values);
},
/**
* Sends a tracking "Event".
* @param {string} category
* @param {string} action
* @param {string} label
* @param {Object} additionalEventParams
*/
send_event: function send_event(
category,
action,
label,
additionalEventParams
) {
if (!label) label = window.location.pathname;
if (!additionalEventParams) additionalEventParams = {};
if (additionalEventParams.mediaLanguage) {
additionalEventParams.ga_cd4 = additionalEventParams.mediaLanguage;
delete additionalEventParams.mediaLanguage;
}
var eventParams = Object.assign(
{
kind: 'event',
ec: category,
ea: action,
el: label,
cache_bust: Math.random(),
},
additionalEventParams
);
this.send_ping(eventParams);
},
/**
* Sends every event instead of a small percentage.
*
* Use this sparingly as it can generate a lot of events.
*
* @param {string} category
* @param {string} action
* @param {string} label
* @param {Object} additionalEventParams
*/
send_event_no_sampling: function send_event_no_sampling(
category,
action,
label,
additionalEventParams
) {
var extraParams = additionalEventParams || {};
extraParams.service = NO_SAMPLING_SERVICE;
this.send_event(category, action, label, extraParams);
},
/**
* @param {Object} options see this.send_pageview options
*/
send_pageview_on_load: function send_pageview_on_load(options) {
var self = this;
window.addEventListener('load', function send_pageview_with_options() {
self.send_pageview(options);
});
},
/**
* Handles tracking events passed in URL.
* Assumes category and action values are separated by a "|" character.
* NOTE: Uses the unsampled analytics property. Watch out for future high click links!
* @param {Location}
*/
process_url_events: function process_url_events(location) {
var eventValues;
var actionValue;
var eventValue = getParams(location).iax;
if (!eventValue) return;
eventValues = eventValue.split('|');
actionValue = eventValues.length >= 1 ? eventValues[1] : '';
this.send_event_no_sampling(
eventValues[0],
actionValue,
window.location.pathname
);
},
/**
* Attaches handlers for event tracking.
*
* To enable click tracking for a link, add a `data-event-click-tracking`
* attribute containing the Google Analytics Event Category and Action, separated
* by a vertical pipe (|).
* e.g. `<a href="foobar" data-event-click-tracking="TopNav|FooBar">`
*
* To enable form submit tracking, add a `data-event-form-tracking` attribute
* to the `form` tag.
* e.g. `<form data-event-form-tracking="TopNav|SearchForm" method="GET">`
*
* Additional tracking options can be added via a `data-event-tracking-options`
* parameter. This parameter, if included, should be a JSON string of the parameters.
* Valid parameters are:
* - service {string}: Corresponds to the Google Analytics property data values flow into
*/
set_up_event_tracking: function set_up_event_tracking() {
var self = this;
var clickTrackingAttributeName = 'event-click-tracking';
var formTrackingAttributeName = 'event-form-tracking';
var trackingOptionsAttributeName = 'event-tracking-options';
function handleAction(event, attributeName) {
var selector = '[data-' + attributeName + ']';
var eventTarget = event.target;
if (!eventTarget) return;
var target = eventTarget.closest(selector);
if (!target) return;
var categoryAction;
var categoryActionParts;
var options;
categoryAction = target.dataset[toCamelCase(attributeName)];
if (!categoryAction) return;
categoryActionParts = categoryAction.split('|');
options = target.dataset[toCamelCase(trackingOptionsAttributeName)];
options = options ? JSON.parse(options) : {};
self.send_event(
categoryActionParts[0],
categoryActionParts[1],
categoryActionParts[2] || window.location.pathname,
options.service ? { service: options.service } : {}
);
}
function toCamelCase(str) {
return str.replace(/\W+(.)/g, function (match, chr) {
return chr.toUpperCase();
});
};
document.addEventListener('click', function(e) {
handleAction(e, clickTrackingAttributeName);
});
document.addEventListener('submit', function(e) {
handleAction(e, formTrackingAttributeName);
});
},
/**
* @returns {Object[]}
*/
get_data_packets: function get_data_packets() {
return [this.values];
},
/**
* Creates a tracking image for tracking JS compatibility.
*
* @param {string} type The type value for track_js_case in query params for 0.gif
*/
create_tracking_image: function create_tracking_image(type) {
this.send_ping_via_image({
cache_bust: Math.random(),
kind: 'track_js',
track_js_case: type,
});
}
};
return ArchiveAnalytics;
}());
// @license-end

500
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/banner-styles.css

@ -0,0 +1,500 @@
@import 'record.css'; /* for SPN1 */
#wm-ipp-base {
height:65px;/* initial height just in case js code fails */
padding:0;
margin:0;
border:none;
background:none transparent;
}
#wm-ipp {
z-index: 2147483647;
}
#wm-ipp, #wm-ipp * {
font-family:Lucida Grande, Helvetica, Arial, sans-serif;
font-size:12px;
line-height:1.2;
letter-spacing:0;
width:auto;
height:auto;
max-width:none;
max-height:none;
min-width:0 !important;
min-height:0;
outline:none;
float:none;
text-align:left;
border:none;
color: #000;
text-indent: 0;
position: initial;
background: none;
}
#wm-ipp div, #wm-ipp canvas {
display: block;
}
#wm-ipp div, #wm-ipp tr, #wm-ipp td, #wm-ipp a, #wm-ipp form {
padding:0;
margin:0;
border:none;
border-radius:0;
background-color:transparent;
background-image:none;
/*z-index:2147483640;*/
height:auto;
}
#wm-ipp table {
border:none;
border-collapse:collapse;
margin:0;
padding:0;
width:auto;
font-size:inherit;
}
#wm-ipp form input {
padding:1px !important;
height:auto;
display:inline;
margin:0;
color: #000;
background: none #fff;
border: 1px solid #666;
}
#wm-ipp form input[type=submit] {
padding:0 8px !important;
margin:1px 0 1px 5px !important;
width:auto !important;
border: 1px solid #000 !important;
background: #fff !important;
color: #000 !important;
}
#wm-ipp a {
display: inline;
}
#wm-ipp a:hover{
text-decoration:underline;
}
#wm-ipp a.wm-btn:hover {
text-decoration:none;
color:#ff0 !important;
}
#wm-ipp a.wm-btn:hover span {
color:#ff0 !important;
}
#wm-ipp #wm-ipp-inside {
margin: 0 6px;
border:5px solid #000;
border-top:none;
background-color:rgba(255,255,255,0.9);
-moz-box-shadow:1px 1px 4px #333;
-webkit-box-shadow:1px 1px 4px #333;
box-shadow:1px 1px 4px #333;
border-radius:0 0 8px 8px;
}
/* selectors are intentionally verbose to ensure priority */
#wm-ipp #wm-logo {
padding:0 10px;
vertical-align:middle;
min-width:100px;
flex: 0 0 100px;
}
#wm-ipp .c {
padding-left: 4px;
}
#wm-ipp .c .u {
margin-top: 4px !important;
}
#wm-ipp .n {
padding:0 0 0 5px !important;
vertical-align: bottom;
}
#wm-ipp .n a {
text-decoration:none;
color:#33f;
font-weight:bold;
}
#wm-ipp .n .b {
padding:0 6px 0 0 !important;
text-align:right !important;
overflow:visible;
white-space:nowrap;
color:#99a;
vertical-align:middle;
}
#wm-ipp .n .y .b {
padding:0 6px 2px 0 !important;
}
#wm-ipp .n .c {
background:#000;
color:#ff0;
font-weight:bold;
padding:0 !important;
text-align:center;
}
#wm-ipp.hi .n td.c {
color:#ec008c;
}
#wm-ipp .n td.f {
padding:0 0 0 6px !important;
text-align:left !important;
overflow:visible;
white-space:nowrap;
color:#99a;
vertical-align:middle;
}
#wm-ipp .n tr.m td {
text-transform:uppercase;
white-space:nowrap;
padding:2px 0;
}
#wm-ipp .c .s {
padding:0 5px 0 0 !important;
vertical-align:bottom;
}
#wm-ipp #wm-nav-captures {
white-space: nowrap;
}
#wm-ipp .c .s a.t {
color:#33f;
font-weight:bold;
line-height: 1.8;
}
#wm-ipp .c .s div.r {
color: #666;
font-size:9px;
white-space:nowrap;
}
#wm-ipp .c .k {
padding-bottom:1px;
}
#wm-ipp .c .s {
padding:0 5px 2px 0 !important;
}
#wm-ipp td#displayMonthEl {
padding: 2px 0 !important;
}
#wm-ipp td#displayYearEl {
padding: 0 0 2px 0 !important;
}
div#wm-ipp-sparkline {
position:relative;/* for positioning markers */
white-space:nowrap;
background-color:#fff;
cursor:pointer;
line-height:0.9;
}
#sparklineImgId, #wm-sparkline-canvas {
position:relative;
z-index:9012;
max-width:none;
}
#wm-ipp-sparkline div.yt {
position:absolute;
z-index:9010 !important;
background-color:#ff0 !important;
top: 0;
}
#wm-ipp-sparkline div.mt {
position:absolute;
z-index:9013 !important;
background-color:#ec008c !important;
top: 0;
}
#wm-ipp .r {
margin-left: 4px;
}
#wm-ipp .r a {
color:#33f;
border:none;
position:relative;
background-color:transparent;
background-repeat:no-repeat !important;
background-position:100% 100% !important;
text-decoration: none;
}
#wm-ipp #wm-capinfo {
/* prevents notice div background from sticking into round corners of
#wm-ipp-inside */
border-radius: 0 0 4px 4px;
}
#wm-ipp #wm-capinfo .c-logo {
display:block;
float:left;
margin-right:3px;
width:90px;
min-height:90px;
max-height: 290px;
border-radius:45px;
overflow:hidden;
background-position:50%;
background-size:auto 90px;
box-shadow: 0 0 2px 2px rgba(208,208,208,128) inset;
}
#wm-ipp #wm-capinfo .c-logo span {
display:inline-block;
}
#wm-ipp #wm-capinfo .c-logo img {
height:90px;
position:relative;
left:-50%;
}
#wm-ipp #wm-capinfo .wm-title {
font-size:130%;
}
#wm-ipp #wm-capinfo a.wm-selector {
display:inline-block;
color: #aaa;
text-decoration:none !important;
padding: 2px 8px;
}
#wm-ipp #wm-capinfo a.wm-selector.selected {
background-color:#666;
}
#wm-ipp #wm-capinfo a.wm-selector:hover {
color: #fff;
}
#wm-ipp #wm-capinfo.notice-only #wm-capinfo-collected-by,
#wm-ipp #wm-capinfo.notice-only #wm-capinfo-timestamps {
display: none;
}
#wm-ipp #wm-capinfo #wm-capinfo-notice .wm-capinfo-content {
background-color:#ff0;
padding:5px;
font-size:14px;
text-align:center;
}
#wm-ipp #wm-capinfo #wm-capinfo-notice .wm-capinfo-content * {
font-size:14px;
text-align:center;
}
#wm-ipp #wm-expand {
right: 1px;
bottom: -1px;
color: #ffffff;
background-color: #666 !important;
padding:0 5px 0 3px !important;
border-radius: 3px 3px 0 0 !important;
}
#wm-ipp #wm-expand span {
color: #ffffff;
}
#wm-ipp #wm-expand #wm-expand-icon {
display: inline-block;
transition: transform 0.5s;
transform-origin: 50% 45%;
}
#wm-ipp #wm-expand.wm-open #wm-expand-icon {
transform: rotate(180deg);
}
#wm-ipp #wmtb {
text-align:right;
}
#wm-ipp #wmtb #wmtbURL {
width: calc(100% - 45px);
}
#wm-ipp #wm-graph-anchor {
border-right:1px solid #ccc;
}
/* time coherence */
html.wb-highlight {
box-shadow: inset 0 0 0 3px #a50e3a !important;
}
.wb-highlight {
outline: 3px solid #a50e3a !important;
}
#wm-ipp-print {
display:none !important;
}
@media print {
#wm-ipp-base {
display:none !important;
}
#wm-ipp-print {
display:block !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
@media (max-width:414px) {
#wm-ipp .xxs {
display:none !important;
}
}
@media (min-width:1055px) {
#wm-ipp #wm-graph-anchor {
display:block !important;
}
}
@media (max-width:1054px) {
#wm-ipp #wm-graph-anchor {
display:none !important;
}
}
@media (max-width:1163px) {
#wm-logo {
display:none !important;
}
}
#wm-btns {
white-space: nowrap;
margin-top: -2px;
}
#wm-btns #wm-save-snapshot-open {
margin-right: 7px;
top: -6px;
}
#wm-btns #wm-sign-in {
box-sizing: content-box;
display: none;
margin-right: 7px;
top: -8px;
/*
round border around sign in button
*/
border: 2px #000 solid;
border-radius: 14px;
padding-right: 2px;
padding-bottom: 2px;
width: 11px;
height: 11px;
}
#wm-btns #wm-sign-in>.iconochive-person {
font-size: 12.5px;
}
#wm-save-snapshot-open > .iconochive-web {
color:#000;
font-size:160%;
}
#wm-ipp #wm-share {
display: flex;
align-items: flex-end;
justify-content: space-between;
}
#wm-share > #wm-screenshot {
display: inline-block;
margin-right: 3px;
visibility: hidden;
}
#wm-screenshot > .iconochive-image {
color:#000;
font-size:160%;
}
#wm-share > #wm-video {
display: inline-block;
margin-right: 3px;
visibility: hidden;
}
#wm-video > .iconochive-movies {
color: #000;
display: inline-block;
font-size: 150%;
margin-bottom: 2px;
}
#wm-btns #wm-save-snapshot-in-progress {
display: none;
font-size:160%;
opacity: 0.5;
position: relative;
margin-right: 7px;
top: -5px;
}
#wm-btns #wm-save-snapshot-success {
display: none;
color: green;
position: relative;
top: -7px;
}
#wm-btns #wm-save-snapshot-fail {
display: none;
color: red;
position: relative;
top: -7px;
}
.wm-icon-screen-shot {
background: url("../images/web-screenshot.svg") no-repeat !important;
background-size: contain !important;
width: 22px !important;
height: 19px !important;
display: inline-block;
}
#donato {
/* transition effect is disable so as to simplify height adjustment */
/*transition: height 0.5s;*/
height: 0;
margin: 0;
padding: 0;
border-bottom: 1px solid #999 !important;
}
body.wm-modal {
height: auto !important;
overflow: hidden !important;
}
#donato #donato-base {
width: 100%;
height: 100%;
/*bottom: 0;*/
margin: 0;
padding: 0;
position: absolute;
z-index: 2147483639;
}
body.wm-modal #donato #donato-base {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2147483640;
}
.wb-autocomplete-suggestions {
font-family: Lucida Grande, Helvetica, Arial, sans-serif;
font-size: 12px;
text-align: left;
cursor: default;
border: 1px solid #ccc;
border-top: 0;
background: #fff;
box-shadow: -1px 1px 3px rgba(0,0,0,.1);
position: absolute;
display: none;
z-index: 2147483647;
max-height: 254px;
overflow: hidden;
overflow-y: auto;
box-sizing: border-box;
}
.wb-autocomplete-suggestion {
position: relative;
padding: 0 .6em;
line-height: 23px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.02em;
color: #333;
}
.wb-autocomplete-suggestion b {
font-weight: bold;
}
.wb-autocomplete-suggestion.selected {
background: #f0f0f0;
}

147
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/bufferlayout.svg

@ -0,0 +1,147 @@
<?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="512"
height="256"
viewBox="0 0 135.46666 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="bufferlayout.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="315.19791"
inkscape:cy="0.98153187"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1">
<sodipodi:guide
position="0,0"
orientation="0,512"
id="guide4485"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,0"
orientation="-256,0"
id="guide4487"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,67.733332"
orientation="0,-512"
id="guide4489"
inkscape:locked="false" />
<sodipodi:guide
position="0,67.733332"
orientation="256,0"
id="guide4491"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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(0,-229.26665)">
<rect
y="260.88434"
x="-0.13229166"
height="31.75"
width="42.333332"
id="rect4519"
style="opacity:1;fill:#008080;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:#00ffff;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4517"
width="42.333332"
height="31.75"
x="-0.13229166"
y="229.13435" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26458333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="135.46666"
height="67.73333"
x="0"
y="229.26665"
rx="2.0798286e-006" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="0.28663194"
y="231.93729"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="0.28663194"
y="231.93729"
style="font-size:2.82222223px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332">(0,0)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="135.18141"
y="296.09872"
id="text4497-5"><tspan
sodipodi:role="line"
id="tspan4495-0"
x="135.18141"
y="296.09872"
style="font-size:2.82222223px;text-align:end;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.26458332">(1023,511)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="20.906906"
y="246.06149"
id="text4523"><tspan
sodipodi:role="line"
id="tspan4521"
x="20.906906"
y="246.06149"
style="fill:#000000;stroke-width:0.26458332">Buffer A</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="20.9951"
y="277.81146"
id="text4523-1"><tspan
sodipodi:role="line"
id="tspan4521-6"
x="20.9951"
y="277.81146"
style="fill:#ffffff;stroke-width:0.26458332">Buffer B</tspan></text>
</g>
</svg>

3
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/bundle-playback.js
File diff suppressed because it is too large
View File

286
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/gpudiagram.svg

@ -0,0 +1,286 @@
<?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="510"
height="320"
viewBox="0 0 134.93749 84.666663"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="gpudiagram.svg">
<title
id="title4564">CPU - GPU Block Diagram</title>
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.2973752"
inkscape:cx="315.52982"
inkscape:cy="174.85259"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:snap-text-baseline="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
units="px"
showguides="true">
<inkscape:grid
type="xygrid"
id="grid4485" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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>CPU - GPU Block Diagram</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-212.33332)">
<path
sodipodi:nodetypes="sccccs"
inkscape:connector-curvature="0"
id="path4580"
d="m 109.8021,254.66666 c 0,-5.29166 5.29166,-5.29166 5.29166,-5.29166 l 15.87499,-1e-5 v 10.58333 l -15.87499,10e-6 c 0,0 -5.29166,0 -5.29166,-5.29167 z"
style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4576"
width="21.166666"
height="9.2604113"
x="80.697914"
y="228.20833" />
<rect
y="228.20833"
x="34.395832"
height="9.2604113"
width="21.166666"
id="rect4574"
style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4572"
width="21.166666"
height="21.166666"
x="80.697914"
y="244.08331" />
<rect
y="244.08333"
x="34.395832"
height="21.166666"
width="21.166666"
id="rect4570"
style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4568"
width="21.166666"
height="21.166666"
x="34.395832"
y="271.86456" />
<rect
y="244.08333"
x="6.614584"
height="21.166666"
width="21.166666"
id="rect4566"
style="opacity:1;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4491"
width="21.166666"
height="21.166666"
x="79.375008"
y="242.76042" />
<rect
y="226.88544"
x="79.375008"
height="9.2604113"
width="21.166666"
id="rect4540"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4524"
width="21.166666"
height="9.2604113"
x="33.072918"
y="226.88544" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4491-9"
width="21.166666"
height="21.166666"
x="33.072918"
y="242.76042" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4556"
width="21.166666"
height="21.166666"
x="5.2916675"
y="242.76041" />
<rect
y="270.54169"
x="33.072918"
height="21.166666"
width="21.166666"
id="rect4518"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:1.25;font-family:HandelGotDLig;-inkscape-font-specification:HandelGotDLig;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="89.958336"
y="254.66667"
id="text4489"><tspan
sodipodi:role="line"
id="tspan4487"
x="89.958336"
y="254.66667"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:2.11666656">GPU</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:1.25;font-family:HandelGotDLig;-inkscape-font-specification:HandelGotDLig;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="43.656254"
y="254.66667"
id="text4489-4"><tspan
sodipodi:role="line"
id="tspan4487-6"
x="43.656254"
y="254.66667"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:2.11666656">CPU</tspan></text>
<text
id="text4516"
y="282.44794"
x="43.656254"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:1.25;font-family:HandelGotDLig;-inkscape-font-specification:HandelGotDLig;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:2.11666656"
y="282.44794"
x="43.656254"
id="tspan4514"
sodipodi:role="line">GTE</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="43.65625"
y="233.50002"
id="text4522"><tspan
sodipodi:role="line"
id="tspan4520"
x="43.65625"
y="233.50002"
style="fill:#000000;stroke:none;stroke-width:0.52916664">RAM</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 43.656254,270.54166 v -6.61458"
id="path4526"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 43.656254,242.76041 v -6.61458"
id="path4528"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 108.47918,253.34374 c 0,-5.29166 5.29166,-5.29166 5.29166,-5.29166 l 15.87499,-1e-5 v 10.58333 l -15.87499,10e-6 c 0,0 -5.29166,0 -5.29166,-5.29167 z"
id="path4530"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sccccs" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 67.46875,291.70832 0,-64.82292"
id="path4532"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="M 54.239587,253.34374 H 79.375004"
id="path4534"
inkscape:connector-curvature="0" />
<text
id="text4538"
y="233.50002"
x="89.958351"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="fill:#000000;stroke:none;stroke-width:0.52916664"
y="233.50002"
x="89.958351"
id="tspan4536"
sodipodi:role="line">VRAM</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 89.958335,242.76041 v -6.61458"
id="path4542"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 100.54168,253.34374 h 7.9375"
id="path4544"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="67.46875"
y="225.56248"
id="text4548"><tspan
sodipodi:role="line"
x="67.46875"
y="225.56248"
style="line-height:1.25;fill:#000000;stroke:none;stroke-width:0.52916664"
id="tspan4550">Bus</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:1.25;font-family:HandelGotDLig;-inkscape-font-specification:HandelGotDLig;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="15.875003"
y="254.66666"
id="text4554"><tspan
sodipodi:role="line"
id="tspan4552"
x="15.875003"
y="254.66666"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:2.11666656">MDEC</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 26.458333,253.34375 h 6.614583"
id="path4558"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="119.0625"
y="254.66666"
id="text4562"><tspan
sodipodi:role="line"
id="tspan4560"
x="119.0625"
y="254.66666"
style="text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.52916664">Video</tspan></text>
</g>
</svg>

116
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/iconochive.css

@ -0,0 +1,116 @@
@font-face{font-family:'Iconochive-Regular';src:url('https://archive.org/includes/fonts/Iconochive-Regular.eot?-ccsheb');src:url('https://archive.org/includes/fonts/Iconochive-Regular.eot?#iefix-ccsheb') format('embedded-opentype'),url('https://archive.org/includes/fonts/Iconochive-Regular.woff?-ccsheb') format('woff'),url('https://archive.org/includes/fonts/Iconochive-Regular.ttf?-ccsheb') format('truetype'),url('https://archive.org/includes/fonts/Iconochive-Regular.svg?-ccsheb#Iconochive-Regular') format('svg');font-weight:normal;font-style:normal}
[class^="iconochive-"],[class*=" iconochive-"]{font-family:'Iconochive-Regular'!important;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
.iconochive-Uplevel:before{content:"\21b5"}
.iconochive-exit:before{content:"\1f6a3"}
.iconochive-beta:before{content:"\3b2"}
.iconochive-logo:before{content:"\1f3db"}
.iconochive-audio:before{content:"\1f568"}
.iconochive-movies:before{content:"\1f39e"}
.iconochive-software:before{content:"\1f4be"}
.iconochive-texts:before{content:"\1f56e"}
.iconochive-etree:before{content:"\1f3a4"}
.iconochive-image:before{content:"\1f5bc"}
.iconochive-web:before{content:"\1f5d4"}
.iconochive-collection:before{content:"\2211"}
.iconochive-folder:before{content:"\1f4c2"}
.iconochive-data:before{content:"\1f5c3"}
.iconochive-tv:before{content:"\1f4fa"}
.iconochive-article:before{content:"\1f5cf"}
.iconochive-question:before{content:"\2370"}
.iconochive-question-dark:before{content:"\3f"}
.iconochive-info:before{content:"\69"}
.iconochive-info-small:before{content:"\24d8"}
.iconochive-comment:before{content:"\1f5e9"}
.iconochive-comments:before{content:"\1f5ea"}
.iconochive-person:before{content:"\1f464"}
.iconochive-people:before{content:"\1f465"}
.iconochive-eye:before{content:"\1f441"}
.iconochive-rss:before{content:"\221e"}
.iconochive-time:before{content:"\1f551"}
.iconochive-quote:before{content:"\275d"}
.iconochive-disc:before{content:"\1f4bf"}
.iconochive-tv-commercial:before{content:"\1f4b0"}
.iconochive-search:before{content:"\1f50d"}
.iconochive-search-star:before{content:"\273d"}
.iconochive-tiles:before{content:"\229e"}
.iconochive-list:before{content:"\21f6"}
.iconochive-list-bulleted:before{content:"\2317"}
.iconochive-latest:before{content:"\2208"}
.iconochive-left:before{content:"\2c2"}
.iconochive-right:before{content:"\2c3"}
.iconochive-left-solid:before{content:"\25c2"}
.iconochive-right-solid:before{content:"\25b8"}
.iconochive-up-solid:before{content:"\25b4"}
.iconochive-down-solid:before{content:"\25be"}
.iconochive-dot:before{content:"\23e4"}
.iconochive-dots:before{content:"\25a6"}
.iconochive-columns:before{content:"\25af"}
.iconochive-sort:before{content:"\21d5"}
.iconochive-atoz:before{content:"\1f524"}
.iconochive-ztoa:before{content:"\1f525"}
.iconochive-upload:before{content:"\1f4e4"}
.iconochive-download:before{content:"\1f4e5"}
.iconochive-favorite:before{content:"\2605"}
.iconochive-heart:before{content:"\2665"}
.iconochive-play:before{content:"\25b6"}
.iconochive-play-framed:before{content:"\1f3ac"}
.iconochive-fullscreen:before{content:"\26f6"}
.iconochive-mute:before{content:"\1f507"}
.iconochive-unmute:before{content:"\1f50a"}
.iconochive-share:before{content:"\1f381"}
.iconochive-edit:before{content:"\270e"}
.iconochive-reedit:before{content:"\2710"}
.iconochive-gear:before{content:"\2699"}
.iconochive-remove-circle:before{content:"\274e"}
.iconochive-plus-circle:before{content:"\1f5d6"}
.iconochive-minus-circle:before{content:"\1f5d5"}
.iconochive-x:before{content:"\1f5d9"}
.iconochive-fork:before{content:"\22d4"}
.iconochive-trash:before{content:"\1f5d1"}
.iconochive-warning:before{content:"\26a0"}
.iconochive-flash:before{content:"\1f5f2"}
.iconochive-world:before{content:"\1f5fa"}
.iconochive-lock:before{content:"\1f512"}
.iconochive-unlock:before{content:"\1f513"}
.iconochive-twitter:before{content:"\1f426"}
.iconochive-facebook:before{content:"\66"}
.iconochive-googleplus:before{content:"\67"}
.iconochive-reddit:before{content:"\1f47d"}
.iconochive-tumblr:before{content:"\54"}
.iconochive-pinterest:before{content:"\1d4df"}
.iconochive-popcorn:before{content:"\1f4a5"}
.iconochive-email:before{content:"\1f4e7"}
.iconochive-embed:before{content:"\1f517"}
.iconochive-gamepad:before{content:"\1f579"}
.iconochive-Zoom_In:before{content:"\2b"}
.iconochive-Zoom_Out:before{content:"\2d"}
.iconochive-RSS:before{content:"\1f4e8"}
.iconochive-Light_Bulb:before{content:"\1f4a1"}
.iconochive-Add:before{content:"\2295"}
.iconochive-Tab_Activity:before{content:"\2318"}
.iconochive-Forward:before{content:"\23e9"}
.iconochive-Backward:before{content:"\23ea"}
.iconochive-No_Audio:before{content:"\1f508"}
.iconochive-Pause:before{content:"\23f8"}
.iconochive-No_Favorite:before{content:"\2606"}
.iconochive-Unike:before{content:"\2661"}
.iconochive-Song:before{content:"\266b"}
.iconochive-No_Flag:before{content:"\2690"}
.iconochive-Flag:before{content:"\2691"}
.iconochive-Done:before{content:"\2713"}
.iconochive-Check:before{content:"\2714"}
.iconochive-Refresh:before{content:"\27f3"}
.iconochive-Headphones:before{content:"\1f3a7"}
.iconochive-Chart:before{content:"\1f4c8"}
.iconochive-Bookmark:before{content:"\1f4d1"}
.iconochive-Documents:before{content:"\1f4da"}
.iconochive-Newspaper:before{content:"\1f4f0"}
.iconochive-Podcast:before{content:"\1f4f6"}
.iconochive-Radio:before{content:"\1f4fb"}
.iconochive-Cassette:before{content:"\1f4fc"}
.iconochive-Shuffle:before{content:"\1f500"}
.iconochive-Loop:before{content:"\1f501"}
.iconochive-Low_Audio:before{content:"\1f509"}
.iconochive-First:before{content:"\1f396"}
.iconochive-Invisible:before{content:"\1f576"}
.iconochive-Computer:before{content:"\1f5b3"}

70
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/style.css

@ -0,0 +1,70 @@
body {
max-width: 900px;
margin: auto;
padding: 8px;
font-family: sans-serif;
font-size: 14px;
//color: white;
//background: black;
}
h {
background-color: #e0e0e0;
padding: 2px;
}
h2 {
border-bottom: 1px solid;
//padding-left: 8px;
}
img {
display: block;
}
.footer-table {
font-size: 14px;
}
.bordered-table {
border-collapse: collapse;
font-size: 11px;
}
.bordered-table th, .bordered-table td {
border: 1px solid;
padding: 4px;
}
hr {
border: none;
border-bottom: 1px solid black;
}
pre {
padding: 8px;
font-size: 12px;
color: black;
background-color: LightGray;
}
/*
FILE ARCHIVED ON 03:35:25 Aug 27, 2022 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 15:39:09 Sep 05, 2022.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
*/
/*
playback timings (ms):
captures_list: 107.165
exclusion.robots: 0.073
exclusion.robots.policy: 0.067
cdx.remote: 0.064
esindex: 0.009
LoadShardBlock: 52.713 (3)
PetaboxLoader3.datanode: 140.466 (4)
CDXLines.iter: 14.771 (3)
load_resource: 139.896
PetaboxLoader3.resolve: 47.824
*/

261
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/vram-layout.svg

@ -0,0 +1,261 @@
<?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="512"
height="256"
viewBox="0 0 135.46666 67.733335"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="vram-layout.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.64868761"
inkscape:cx="283.23648"
inkscape:cy="175.65817"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="false"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-text-baseline="true"
showguides="false"
inkscape:pagecheckerboard="false"
borderlayer="true">
<inkscape:grid
type="xygrid"
id="grid5145" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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(0,-229.26665)">
<rect
y="260.75208"
x="0"
height="31.487331"
width="42.070667"
id="rect4519"
style="opacity:1;fill:#008080;fill-opacity:1;stroke:#000000;stroke-width:0.26266789;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:#00ffff;fill-opacity:1;stroke:#000000;stroke-width:0.26226139;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4517"
width="42.071072"
height="31.48774"
x="0"
y="229.26665" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="135.46666"
height="67.73333"
x="7.1207683e-006"
y="229.26666"
rx="2.0798286e-006"
ry="2.0798286e-006" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="0.28663194"
y="231.93729"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="0.28663194"
y="231.93729"
style="font-size:2.82222223px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332">(0,0)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="135.18141"
y="296.09872"
id="text4497-5"><tspan
sodipodi:role="line"
id="tspan4495-0"
x="135.18141"
y="296.09872"
style="font-size:2.82222223px;text-align:end;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.26458332">(1023,511)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="20.906906"
y="246.06149"
id="text4523"><tspan
sodipodi:role="line"
id="tspan4521"
x="20.906906"
y="246.06149"
style="fill:#000000;stroke-width:0.26458332">Buffer A</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="20.9951"
y="277.81146"
id="text4523-1"><tspan
sodipodi:role="line"
id="tspan4521-6"
x="20.9951"
y="277.81146"
style="fill:#ffffff;stroke-width:0.26458332">Buffer B</tspan></text>
<rect
style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:0.26378265;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5147"
width="42.068748"
height="4.7624955"
x="0"
y="292.23749" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888855px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="19.84375"
y="295.67706"
id="text5151"><tspan
sodipodi:role="line"
id="tspan5149"
x="19.84375"
y="295.67706"
style="font-size:2.82222223px;fill:#000000;stroke:none;stroke-width:0.52916664">CLUTS</tspan></text>
<rect
style="opacity:1;fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.26253229;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5153"
width="33.602085"
height="33.868713"
x="42.068748"
y="229.2646" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="59.267689"
y="246.46355"
id="text5161"><tspan
sodipodi:role="line"
id="tspan5159"
x="59.267689"
y="246.46355"
style="fill:#000000;stroke-width:0.52916664">Textures</tspan></text>
<rect
y="229.2646"
x="75.67083"
height="33.868713"
width="33.602085"
id="rect5163"
style="opacity:1;fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.26253229;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5167"
y="246.46356"
x="93.134361"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="fill:#000000;stroke-width:0.52916664"
y="246.46356"
x="93.134361"
id="tspan5165"
sodipodi:role="line">Textures</tspan></text>
<rect
y="263.13333"
x="42.068748"
height="33.866684"
width="33.604134"
id="rect5183"
style="opacity:1;fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.26253229;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5187"
y="280.59479"
x="59.267689"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="fill:#000000;stroke-width:0.52916664"
y="280.59479"
x="59.267689"
id="tspan5185"
sodipodi:role="line">Textures</tspan></text>
<rect
style="opacity:1;fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.26253229;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5189"
width="33.60413"
height="33.866653"
x="75.67083"
y="263.13333" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="93.134361"
y="280.59479"
id="text5193"><tspan
sodipodi:role="line"
id="tspan5191"
x="93.134361"
y="280.59479"
style="fill:#000000;stroke-width:0.52916664">Textures</tspan></text>
<rect
style="opacity:1;fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5195"
width="13.229165"
height="20.108335"
x="109.27292"
y="229.26665" />
<rect
style="opacity:1;fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5199"
width="12.964583"
height="20.108335"
x="122.50208"
y="229.26665" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="115.8875"
y="240.11456"
id="text5203"><tspan
sodipodi:role="line"
id="tspan5201"
x="115.8875"
y="240.11456"
style="fill:#000000;stroke-width:0.52916664">Textures</tspan></text>
<text
id="text5207"
y="240.11456"
x="129.11667"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52916664;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="fill:#000000;stroke-width:0.52916664"
y="240.11456"
x="129.11667"
id="tspan5205"
sodipodi:role="line">Textures</tspan></text>
</g>
</svg>

21
Docs/Chapter 1.1 Setting up Graphics and Hello World_files/wombat.js
File diff suppressed because it is too large
View File

413
Docs/Chapter 1.2 Drawing Graphics.htm

@ -0,0 +1,413 @@
<html><head><script src="Chapter%201.2%20Drawing%20Graphics_files/analytics.js" type="text/javascript"></script>
<script type="text/javascript">window.addEventListener('DOMContentLoaded',function(){var v=archive_analytics.values;v.service='wb';v.server_name='wwwb-app228.us.archive.org';v.server_ms=369;archive_analytics.send_pageview({});});</script>
<script type="text/javascript" src="Chapter%201.2%20Drawing%20Graphics_files/bundle-playback.js" charset="utf-8"></script>
<script type="text/javascript" src="Chapter%201.2%20Drawing%20Graphics_files/wombat.js" charset="utf-8"></script>
<script type="text/javascript">
__wm.init("http://web.archive.org/web");
__wm.wombat("http://lameguy64.net/tutorials/pstutorials/chapter1/2-graphics.html","20220827033534","http://web.archive.org/","web","/_static/",
"1661571334");
</script>
<link rel="stylesheet" type="text/css" href="Chapter%201.2%20Drawing%20Graphics_files/banner-styles.css">
<link rel="stylesheet" type="text/css" href="Chapter%201.2%20Drawing%20Graphics_files/iconochive.css">
<!-- End Wayback Rewrite JS Include -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="Chapter%201.2%20Drawing%20Graphics_files/style.css">
<title>Chapter 1.2: Drawing Graphics</title><meta http-equiv="Content-Type" content="text/html; charset=windows-1252"></head>
<body><!-- BEGIN WAYBACK TOOLBAR INSERT -->
<style type="text/css">
body {
margin-top:0 !important;
padding-top:0 !important;
/*min-width:800px !important;*/
}
</style>
<script>__wm.rw(0);</script>
<div id="wm-ipp-base" style="display: block; direction: ltr; height: 1px;" lang="en">
</div><div id="wm-ipp-print">The Wayback Machine -
http://web.archive.org/web/20220827033534/http://lameguy64.net/tutorials/pstutorials/chapter1/2-graphics.html</div>
<script type="text/javascript">//<![CDATA[
__wm.bt(675,27,25,2,"web","http://lameguy64.net/tutorials/pstutorials/chapter1/2-graphics.html","20220827033534",1996,"/_static/",["/_static/css/banner-styles.css?v=fantwOh2","/_static/css/iconochive.css?v=qtvMKcIJ"], false);
__wm.rw(1);
//]]></script>
<!-- END WAYBACK TOOLBAR INSERT -->
<h1>1.2. Drawing Graphics</h1>
<p>This tutorial will teach you how to draw graphics primitives with the GPU
using an ordering table and primitive packets. This is a very essential part
to learn about the PS1 as you need graphics to do anything on the console
really.</p>
<p>Just like in the last tutorial, libgs will not be covered here. Also, the
GPU is not responsible for 3D graphics. While it does render out (affine)
polygon all the 3D processing is actually done in a co-processor, called
the GTE or Geometry Transformation Engine.</p>
<p><b><i>Trivia:</i></b> The easiest way to tell if a person is not a PS1 programmer
is if they call the GTE the Geometry <i>Transfer</i> Engine instead of
<b>Transformation</b> Engine. The GTE does NOT transfer anything, it is
essentially like a math co-processor on the CPU as nothing but the CPU has
access to it, and it does nothing else but vector transformations that helps
greatly in 3D graphics processing.</p>
<p><b>Tutorial compatible with PSn00bSDK:</b>Yes</p>
<h2>Tutorial Index</h2>
<ul>
<li><a href="#operation">Theory of Operation</a></li>
<li><a href="#ordertable">Ordering Tables</a></li>
<li><a href="#primitives">Primitive Packets</a></li>
<li><a href="#primprep">Preparing a Primitive</a></li>
<li><a href="#primbuff">Primitive Buffers</a></li>
<li><a href="#otsort">Sorting a Primitive to an Ordering Table</a></li>
<li><a href="#otdraw">Drawing an Ordering Table</a></li>
<li><a href="#doublebuff">Double Ordering Tables/Primitive Buffers</a></li>
<li><a href="#samplecode">Sample Code</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
<h2 id="operation">Theory of Operation</h2>
<p>The PS1 GPU draws graphics by means of primitive packets, which are
essentially messages that command the GPU to draw a specified primitive
in a specified color to specified screen coordinates to name a few.</p>
<p>Drawing packets are normally sent to the GPU by an ordering table,
which is essentially an array of pointers that form a chain. Primitive
packets are normally linked to the ordering table to draw them.</p>
<h2 id="ordertable">Ordering Tables</h2>
<p>An ordering table is an array of elements of pointers that point from
one element to another, the ordering table usually ends with an array element
with the value of 0xFFFFFFFF which is used as a terminator value for ordering
table processing. An ordering table is normally created using <b>ClearOTagR()</b>
on an array of 32-bit ints.</p>
<p>The following figure visually describes the general structure of an ordering table.</p>
<img src="Chapter%201.2%20Drawing%20Graphics_files/ordertable.svg">
<p>Adding primitives to an ordering table is normally achieved using
<b>addPrim()/AddPrim()</b> functions. <b>DrawOTag()</b> is used to begin
processing of an ordering table.</p>
<p>The type of ordering table shown above is called a reverse ordering table
because the chain starts at the end of the array and ends at the beginning of
the array. This type of ordering table is most commonly used as the reverse
order allows for depth ordering of polygons which is essential for 3D graphics.
Use <b>ClearOTag()</b> if you wish to use a non-reverse ordering table but the
initialization speed won't be as fast as <b>ClearOTagR()</b> for larger tables
as <b>ClearOTagR()</b> is DMA accelerated, but it can only generate reverse
ordering tables.</p>
<p>For simplicity, a global ordering table array of 8 elements should suffice
for this tutorial.</p>
<pre>int ot[2][8];
</pre>
<p>The reason two arrays of <h>ot</h> are defined is for double buffered
rendering reasons, which will be explained later in this tutorial.</p>
<h2 id="primitives">Primitive Packets</h2>
<p>Primitive packets are more or less commands that instruct the GPU to draw
a specified primitive to specified coordinates of the drawing area carried by
the packet. Primitive packets are always aligned 4-byte aligned.</p>
<p>The following illustrates the typical structure of a primitive packet
(the packet represents a <b>SPRT</b> primitive):</p>
<img src="Chapter%201.2%20Drawing%20Graphics_files/primstruct.svg">
<p>C implementation of the above structure</p>
<pre>typedef struct {
unsigned int tag; // First 24 bits are address, last 8 bits are length
unsigned char r0,g0,b0,code; // RGB color and primitive code
short x0,y0; // X,Y coordinates of sprite
unsigned char u0,v0; // U,V texture coordinates of sprite
unsigned short clut; // Texture CLUT
unsigned short w,h; // Sprite width and height
} SPRT;
</pre>
<p>The number of parameter words of a primitive packet varies on the primitive
command. Simpler commands such as a fixed sized, solid color sprite is only 3
words long whereas a shaded, textured 4-point polygon is 13 words long, the
length of the primitive in words is specified to the <i>Len</i> field minus the
tag word. The <i>Next Pointer</i> field is an address to the next primitive or
return pointer to an ordering table it was sorted to.</p>
<p>A word in this context is a 4 byte integer.</p>
<p>Primitives are normally defined using primitive structures and macros
defined in libgpu.h, or psxgpu.h in PSn00bSDK.</p>
<h2 id="primprep">Preparing a Primitive</h2>
<p>Primitive packets are normally prepared using primitive structures and
macros. A solid color rectangular sprite (<b>TILE</b>) will be used for this
tutorial.</p>
<p>Primitive preparation is as follows.</p>
<pre>TILE tile; // Primitive structure
setTile(&amp;tile;); // Initialize the primitive (very important)
setXY0(&amp;tile;, 32, 32); // Set primitive (x,y) position
setWH(&amp;tile;, 64, 64); // Set primitive size
setRGB0(&amp;tile;, 255, 255, 0); // Set color yellow
</pre>
<p>The <b>setTile()</b> macro simply fills in the appropriate values to the tag
length and primitive code fields to the specified primitive. These values are
mandatory and must be correct, otherwise the GPU will lock up. Always use the
appropriate initializer macro for a primitive.</p>
<p>The <b>setXY0()</b>, <b>setWH()</b> and <b>setRGB0()</b> macros sets the
(x,y) coordinates, size and color of the primitive respectively. While the
fields of a primitive can be set directly via struct elements of the
primitive, using macros helps make the code looking tidy.</p>
<p>Normally, primitive packets are defined to a primitive buffer.</p>
<h2 id="primbuff">Primitive Buffers</h2>
<p>A primitive buffer is simply a global array of char elements used as a
buffer to define primitive packets to. It is also a lot less wasteful than
defining multiple arrays for different primitive types as all primitive types
can be defined in just a single global buffer.</p>
<p>The reason it is recommended that primitive packets must be defined in a
global buffer is because the primitives must exist in memory until the GPU
gets around to processing it. If you were to define primitives as a local
variable in a function and register it to an ordering table, that primitive
has most likely been overwritten by other things (since locals are generally
temporary variables), resulting in a corrupted ordering table which would
result to a GPU lock up or crash.</p>
<p>A primitive buffer can be defined as such, 32KB buffer for primitives
should be plenty.</p>
<pre>char primbuff[2][32768];
char *nextpri;
</pre>
<p>The <h>nextpri</h> variable will be used to keep track where the next
primitive should be written to. Therefore, this variable must be set to
the first primitive buffer and reset in your display function.</p>
<p>To prepare a primitive to the primitive buffer, simply cast the
nextpri pointer into a primitive pointer.</p>
<pre>TILE *tile; // Primitive pointer
tile = (TILE*)nextpri; // Cast hext primitive
setTile(tile); // Initialize the primitive (very important)
setXY0(tile, 32, 32); // Set primitive (x,y) position
setWH(tile, 64, 64); // Set primitive size
setRGB0(tile, 255, 255, 0); // Set color yellow
</pre>
<p>After registering the primitive to the ordering table, you'll want to
advance the <i>nextpri</i> pointer for another primitive to be written to.</p>
<pre>nextpri += sizeof(TILE);
</pre>
<p>It is very important to advance this pointer, otherwise previously defined
packets would get overwritten, corrupting the primitive buffer.</p>
<h2 id="otsort">Sorting a Primitive to an Ordering Table</h2>
<p>The term 'sorting' in the context of PS1 graphics programming refers to
linking a primitive to an ordering table element. Its often called sorting
because an ordering table is also used to control the order of which
primitives are drawn. In a reverse ordering table (initialized using
ClearOTagR()) a primitive sorted highest will be drawn first and primitives
sorted lowest will be drawn last, which would make a lot of sense in 3D
graphics.</p>
<p>Sorting a primitive to an ordering table is achieved using the
<b>addPrim()</b> macro.</p>
<pre>addPrim(ot[db], tile);
</pre>
<p>There's also a function version called <b>AddPrim()</b> but the macro version
would be faster in the long run, mainly because code jumps are kept a minimum when
using macros.</p>
<p>Taking the code snippet earlier, this is the process of how to create and sort
a primitive to be drawn.</p>
<pre>tile = (TILE*)nextpri; // Cast next primitive
setTile(tile); // Initialize the primitive (very important)
setXY0(tile, 32, 32); // Set primitive (x,y) position
setWH(tile, 64, 64); // Set primitive size
setRGB0(tile, 255, 255, 0); // Set color yellow
addPrim(ot[db], tile); // Add primitive to the ordering table
nextpri += sizeof(TILE); // Advance the next primitive pointer
</pre>
<p>Primitives need to be sorted to an ordering table for the GPU to process it.
To sort the primitive to a higher ordering table element, simply use (+) to
increment the ordering table address. But don't increment by a value that
will exceed the length of your ordering table, or that will result to memory
overflow corruption.</p>
<p>Sorting a primitive to an ordering table links the specified primitive into
the chain, so it gets processed when the OT is proceessed by the GPU. The
following figure visually describes the result of sorting a primitive to ordering
table element 4.</p>
<img src="Chapter%201.2%20Drawing%20Graphics_files/ordertable-primitive.svg">
<p>A very common misconception among many PS1 homebrew programmers is they believe
only a single primitive can be sorted to an ordering table element. This is
absolutely untrue because sorting a primitive to an element that has a primitive
already linked to it will only add further to the chain, not replace the previous
element.</p>
<img src="Chapter%201.2%20Drawing%20Graphics_files/ordertable-multiprims.svg">
<p>You can sort any number of primitives to a single ordering table, so an ordering
table of 4 to 8 elements should be sufficient for 2D projects. But remember that the
newest primitive sorted will be the first to be processed, as shown in the figure
earlier.</p>
<h2 id="otdraw">Drawing an Ordering Table</h2>
<p>Ordering table processing is done using the <b>DrawOTag()</b> function.
<b>DrawOTag()</b> starts a DMA transfer process of the specified ordering
table for the GPU to process. This is the most recommended method of
processing ordering tables as this is the fastest way to deliver graphics
primitives to the GPU.</p>
<p>Since this tutorial demonstrates the use of a reverse ordering table, the
last element of the ordering table must be specified to <b>DrawOTag()</b>, as
the chain starts at the last element and ends at the first.</p>
<pre>DrawOTag(ot[db]+31);
</pre>
<p>The transfer operation is asynchronous so the function returns very
quickly. It is recommended to wait for the transfer and the GPU to finish
processing which is achieved using <b>DrawSync()</b> before processing another
ordering table.</p>
<h2 id="doublebuff">Double Ordering Tables/Primitive Buffers</h2>
<p>You may have noticed by now that ordering tables and primitive buffers are
defined in pairs. This is so that a commonly used optimization trick can be
achieved and is another form of double buffering. Because the CPU can continue
running while the GPU is busy processing graphics, you can utilize this to
continue processing graphics primitives for drawing the next frame while the
GPU is drawing. The following figure visually describes the performance
difference.</p>
<img src="Chapter%201.2%20Drawing%20Graphics_files/ordertable-buffercompare.svg">
<p>Having double buffers essentially minimizes keeping the GPU idle which
comes off as being most efficient, as having single buffers would prevent
you from preparing primitives for the next frame which results to leaving
the GPU in an idle state. While this may not be apparent in small programs,
it will be once you start pushing the GPU with thousands of primitives.</p>
<h2 id="samplecode">Sample Code</h2>
<p>The sample code works off of the one from the previous example, but with
graphics drawing code implemented.</p>
<pre>#include &lt;sys/types.h&gt; // This provides typedefs needed by libgte.h and libgpu.h
#include &lt;stdio.h&gt; // Not necessary but include it anyway
#include &lt;libetc.h&gt; // Includes some functions that controls the display
#include &lt;libgte.h&gt; // GTE header, not really used but libgpu.h depends on it
#include &lt;libgpu.h&gt; // GPU library header
#define OTLEN 8 // Ordering table length (recommended to set as a define
// so it can be changed easily)
DISPENV disp[2];
DRAWENV draw[2];
int db = 0;
u_long ot[2][OTLEN]; // Ordering table length
char pribuff[2][32768]; // Primitive buffer
char *nextpri; // Next primitive pointer
void display() {
DrawSync(0); // Wait for any graphics processing to finish
VSync(0); // Wait for vertical retrace
PutDispEnv(&amp;disp;[db]); // Apply the DISPENV/DRAWENVs
PutDrawEnv(&amp;draw;[db]);
SetDispMask(1); // Enable the display
DrawOTag(ot[db]+OTLEN-1); // Draw the ordering table
db = !db; // Swap buffers on every pass (alternates between 1 and 0)
nextpri = pribuff[db]; // Reset next primitive pointer
}
int main() {
TILE *tile; // Primitive pointer
// Reset graphics
ResetGraph(0);
// First buffer
SetDefDispEnv(&amp;disp;[0], 0, 0, 320, 240);
SetDefDrawEnv(&amp;draw;[0], 0, 240, 320, 240);
// Second buffer
SetDefDispEnv(&amp;disp;[1], 0, 240, 320, 240);
SetDefDrawEnv(&amp;draw;[1], 0, 0, 320, 240);
draw[0].isbg = 1; // Enable clear
setRGB0(&amp;draw;[0], 63, 0, 127); // Set clear color (dark purple)
draw[1].isbg = 1;
setRGB0(&amp;draw;[1], 63, 0, 127);
nextpri = pribuff[0]; // Set initial primitive pointer address
while(1) {
ClearOTagR(ot[db], OTLEN); // Clear ordering table
tile = (TILE*)nextpri; // Cast next primitive
setTile(tile); // Initialize the primitive (very important)
setXY0(tile, 32, 32); // Set primitive (x,y) position
setWH(tile, 64, 64); // Set primitive size
setRGB0(tile, 255, 255, 0); // Set color yellow
addPrim(ot[db], tile); // Add primitive to the ordering table
nextpri += sizeof(TILE); // Advance the next primitive pointer
// Update the display
display();
}
return 0;
}
</pre>
<p>Compile and run the program and you should get a yellow square.
Your very first graphic done with the GPU!</p>
<img src="Chapter%201.2%20Drawing%20Graphics_files/2-graphics.png">
<h2 id="conclusion">Conclusion</h2>
<p>This concludes Chapter 1.2. of Lameguy64's PSX Tutorial series.
You should know more about drawing graphics on the PS1 after reading
through this chapter.</p>
<p>A few things you may want to experiment with yourself for further
learning:</p>
<ul>
<li>Play around with the values specified in <b>setXY0()</b>, <b>setRGB0()</b>
and <b>setWH()</b> to change the position, color and size of the sprite
respectively.</li>
<li>Try drawing more sprites by repeating the primitive creation process.
Make sure the <h>nextpri</h> and <h>tile</h> pointers have been advanced before
creating a new primitive.</li>
<li>You can advance the primitive pointer with <h>tile++;</h>, and set the
updated address to <h>nextpri</h> by converting types back
(<h>nextpri = (char*)tile;</h>)</li>
<li>Try making the yellow square bounce around the screen, by defining
two variables for (x,y) coordinates and two more for the direction flags,
and write some logic that makes the (x,y) coordinates move and bounce
around the screen.</li>
</ul>
<p>The next tutorial will cover how to convert and upload texture data, as
well as drawing said textures with sprite and polygon primitives.</p>
<hr>
<table class="footer-table" width="100%">
<tbody><tr>
<td width="40%" align="left"><a href="http://web.archive.org/web/20220827033534/http://lameguy64.net/tutorials/pstutorials/chapter1/1-display.html">Previous</a></td>
<td width="20%" align="center"><a href="http://web.archive.org/web/20220827033534/http://lameguy64.net/tutorials/pstutorials/index.html">Back to Index</a></td>
<td width="40%" align="right"><a href="http://web.archive.org/web/20220827033534/http://lameguy64.net/tutorials/pstutorials/chapter1/3-textures.html">Next</a></td>
</tr>
</tbody></table>
</body></html>
<!--
FILE ARCHIVED ON 03:35:34 Aug 27, 2022 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 15:40:29 Sep 05, 2022.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->
<!--
playback timings (ms):
captures_list: 241.637
exclusion.robots: 0.473
exclusion.robots.policy: 0.464
RedisCDXSource: 14.466
esindex: 0.01
LoadShardBlock: 195.528 (3)
PetaboxLoader3.datanode: 171.89 (4)
CDXLines.iter: 27.223 (3)
load_resource: 118.452
PetaboxLoader3.resolve: 85.381
-->

474
Docs/Chapter 1.2 Drawing Graphics_files/analytics.js

@ -0,0 +1,474 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0
/* eslint-disable no-var, semi, prefer-arrow-callback, prefer-template */
/**
* Collection of methods for sending analytics events to Archive.org's analytics server.
*
* These events are used for internal stats and sent (in anonymized form) to Google Analytics.
*
* @see analytics.md
*
* @type {Object}
*/
window.archive_analytics = (function defineArchiveAnalytics() {
// keep orignal Date object so as not to be affected by wayback's
// hijacking global Date object
var Date = window.Date;
var ARCHIVE_ANALYTICS_VERSION = 2;
var DEFAULT_SERVICE = 'ao_2';
var NO_SAMPLING_SERVICE = 'ao_no_sampling'; // sends every event instead of a percentage
var startTime = new Date();
/**
* @return {Boolean}
*/
function isPerformanceTimingApiSupported() {
return 'performance' in window && 'timing' in window.performance;
}
/**
* Determines how many milliseconds elapsed between the browser starting to parse the DOM and
* the current time.
*
* Uses the Performance API or a fallback value if it's not available.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
*
* @return {Number}
*/
function getLoadTime() {
var start;
if (isPerformanceTimingApiSupported())
start = window.performance.timing.domLoading;
else
start = startTime.getTime();
return new Date().getTime() - start;
}
/**
* Determines how many milliseconds elapsed between the user navigating to the page and
* the current time.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
*
* @return {Number|null} null if the browser doesn't support the Performance API
*/
function getNavToDoneTime() {
if (!isPerformanceTimingApiSupported())
return null;
return new Date().getTime() - window.performance.timing.navigationStart;
}
/**
* Performs an arithmetic calculation on a string with a number and unit, while maintaining
* the unit.
*
* @param {String} original value to modify, with a unit
* @param {Function} doOperation accepts one Number parameter, returns a Number
* @returns {String}
*/
function computeWithUnit(original, doOperation) {
var number = parseFloat(original, 10);
var unit = original.replace(/(\d*\.\d+)|\d+/, '');
return doOperation(number) + unit;
}
/**
* Computes the default font size of the browser.
*
* @returns {String|null} computed font-size with units (typically pixels), null if it cannot be computed
*/
function getDefaultFontSize() {
var fontSizeStr;
if (!('getComputedStyle' in window))
return null;
var style = window.getComputedStyle(document.documentElement);
if (!style)
return null;
fontSizeStr = style.fontSize;
// Don't modify the value if tracking book reader.
if (document.querySelector('#BookReader'))
return fontSizeStr;
return computeWithUnit(fontSizeStr, function reverseBootstrapFontSize(number) {
// Undo the 62.5% size applied in the Bootstrap CSS.
return number * 1.6;
});
}
/**
* Get the URL parameters for a given Location
* @param {Location}
* @return {Object} The URL parameters
*/
function getParams(location) {
if (!location) location = window.location;
var vars;
var i;
var pair;
var params = {};
var query = location.search;
if (!query) return params;
vars = query.substring(1).split('&');
for (i = 0; i < vars.length; i++) {
pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
}
function getMetaProp(name) {
var metaTag = document.querySelector('meta[property=' + name + ']');
return metaTag ? metaTag.getAttribute('content') || null : null;
}
var ArchiveAnalytics = {
/**
* @type {String|null}
*/
service: getMetaProp('service'),
mediaType: getMetaProp('mediatype'),
primaryCollection: getMetaProp('primary_collection'),
/**
* Key-value pairs to send in pageviews (you can read this after a pageview to see what was
* sent).
*
* @type {Object}
*/
values: {},
/**
* Sends an analytics ping, preferably using navigator.sendBeacon()
* @param {Object} values
* @param {Function} [onload_callback] (deprecated) callback to invoke once ping to analytics server is done
* @param {Boolean} [augment_for_ao_site] (deprecated) if true, add some archive.org site-specific values
*/
send_ping: function send_ping(values, onload_callback, augment_for_ao_site) {
if (typeof window.navigator !== 'undefined' && typeof window.navigator.sendBeacon !== 'undefined')
this.send_ping_via_beacon(values);
else
this.send_ping_via_image(values);
},
/**
* Sends a ping via Beacon API
* NOTE: Assumes window.navigator.sendBeacon exists
* @param {Object} values Tracking parameters to pass
*/
send_ping_via_beacon: function send_ping_via_beacon(values) {
var url = this.generate_tracking_url(values || {});
window.navigator.sendBeacon(url);
},
/**
* Sends a ping via Image object
* @param {Object} values Tracking parameters to pass
*/
send_ping_via_image: function send_ping_via_image(values) {
var url = this.generate_tracking_url(values || {});
var loadtime_img = new Image(1, 1);
loadtime_img.src = url;
loadtime_img.alt = '';
},
/**
* Construct complete tracking URL containing payload
* @param {Object} params Tracking parameters to pass
* @return {String} URL to use for tracking call
*/
generate_tracking_url: function generate_tracking_url(params) {
var baseUrl = '//analytics.archive.org/0.gif';
var keys;
var outputParams = params;
var outputParamsArray = [];
outputParams.service = outputParams.service || this.service || DEFAULT_SERVICE;
// Build array of querystring parameters
keys = Object.keys(outputParams);
keys.forEach(function keyIteration(key) {
outputParamsArray.push(encodeURIComponent(key) + '=' + encodeURIComponent(outputParams[key]));
});
outputParamsArray.push('version=' + ARCHIVE_ANALYTICS_VERSION);
outputParamsArray.push('count=' + (keys.length + 2)); // Include `version` and `count` in count
return baseUrl + '?' + outputParamsArray.join('&');
},
/**
* @param {int} page Page number
*/
send_scroll_fetch_event: function send_scroll_fetch_event(page) {
var additionalValues = { ev: page };
var loadTime = getLoadTime();
var navToDoneTime = getNavToDoneTime();
if (loadTime) additionalValues.loadtime = loadTime;
if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
this.send_event('page_action', 'scroll_fetch', location.pathname, additionalValues);
},
send_scroll_fetch_base_event: function send_scroll_fetch_base_event() {
var additionalValues = {};
var loadTime = getLoadTime();
var navToDoneTime = getNavToDoneTime();
if (loadTime) additionalValues.loadtime = loadTime;
if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
this.send_event('page_action', 'scroll_fetch_base', location.pathname, additionalValues);
},
/**
* @param {Object} [options]
* @param {String} [options.mediaType]
* @param {String} [options.mediaLanguage]
* @param {String} [options.page] The path portion of the page URL
*/
send_pageview: function send_pageview(options) {
var settings = options || {};
var defaultFontSize;
var loadTime = getLoadTime();
var mediaType = settings.mediaType;
var primaryCollection = settings.primaryCollection;
var page = settings.page;
var navToDoneTime = getNavToDoneTime();
/**
* @return {String}
*/
function get_locale() {
if (navigator) {
if (navigator.language)
return navigator.language;
else if (navigator.browserLanguage)
return navigator.browserLanguage;
else if (navigator.systemLanguage)
return navigator.systemLanguage;
else if (navigator.userLanguage)
return navigator.userLanguage;
}
return '';
}
defaultFontSize = getDefaultFontSize();
// Set field values
this.values.kind = 'pageview';
this.values.timediff = (new Date().getTimezoneOffset()/60)*(-1); // *timezone* diff from UTC
this.values.locale = get_locale();
this.values.referrer = (document.referrer == '' ? '-' : document.referrer);
if (loadTime)
this.values.loadtime = loadTime;
if (navToDoneTime)
this.values.nav_to_done_ms = navToDoneTime;
if (settings.trackingId) {
this.values.ga_tid = settings.trackingId;
}
/* START CUSTOM DIMENSIONS */
if (defaultFontSize)
this.values.ga_cd1 = defaultFontSize;
if ('devicePixelRatio' in window)
this.values.ga_cd2 = window.devicePixelRatio;
if (mediaType)
this.values.ga_cd3 = mediaType;
if (settings.mediaLanguage) {
this.values.ga_cd4 = settings.mediaLanguage;
}
if (primaryCollection) {
this.values.ga_cd5 = primaryCollection;
}
/* END CUSTOM DIMENSIONS */
if (page)
this.values.page = page;
this.send_ping(this.values);
},
/**
* Sends a tracking "Event".
* @param {string} category
* @param {string} action
* @param {string} label
* @param {Object} additionalEventParams
*/
send_event: function send_event(
category,
action,
label,
additionalEventParams
) {
if (!label) label = window.location.pathname;
if (!additionalEventParams) additionalEventParams = {};
if (additionalEventParams.mediaLanguage) {
additionalEventParams.ga_cd4 = additionalEventParams.mediaLanguage;
delete additionalEventParams.mediaLanguage;
}
var eventParams = Object.assign(
{
kind: 'event',
ec: category,
ea: action,
el: label,
cache_bust: Math.random(),
},
additionalEventParams
);
this.send_ping(eventParams);
},
/**
* Sends every event instead of a small percentage.
*
* Use this sparingly as it can generate a lot of events.
*
* @param {string} category
* @param {string} action
* @param {string} label
* @param {Object} additionalEventParams
*/
send_event_no_sampling: function send_event_no_sampling(
category,
action,
label,
additionalEventParams
) {
var extraParams = additionalEventParams || {};
extraParams.service = NO_SAMPLING_SERVICE;
this.send_event(category, action, label, extraParams);
},
/**
* @param {Object} options see this.send_pageview options
*/
send_pageview_on_load: function send_pageview_on_load(options) {
var self = this;
window.addEventListener('load', function send_pageview_with_options() {
self.send_pageview(options);
});
},
/**
* Handles tracking events passed in URL.
* Assumes category and action values are separated by a "|" character.
* NOTE: Uses the unsampled analytics property. Watch out for future high click links!
* @param {Location}
*/
process_url_events: function process_url_events(location) {
var eventValues;
var actionValue;
var eventValue = getParams(location).iax;
if (!eventValue) return;
eventValues = eventValue.split('|');
actionValue = eventValues.length >= 1 ? eventValues[1] : '';
this.send_event_no_sampling(
eventValues[0],
actionValue,
window.location.pathname
);
},
/**
* Attaches handlers for event tracking.
*
* To enable click tracking for a link, add a `data-event-click-tracking`
* attribute containing the Google Analytics Event Category and Action, separated
* by a vertical pipe (|).
* e.g. `<a href="foobar" data-event-click-tracking="TopNav|FooBar">`
*
* To enable form submit tracking, add a `data-event-form-tracking` attribute
* to the `form` tag.
* e.g. `<form data-event-form-tracking="TopNav|SearchForm" method="GET">`
*
* Additional tracking options can be added via a `data-event-tracking-options`
* parameter. This parameter, if included, should be a JSON string of the parameters.
* Valid parameters are:
* - service {string}: Corresponds to the Google Analytics property data values flow into
*/
set_up_event_tracking: function set_up_event_tracking() {
var self = this;
var clickTrackingAttributeName = 'event-click-tracking';
var formTrackingAttributeName = 'event-form-tracking';
var trackingOptionsAttributeName = 'event-tracking-options';
function handleAction(event, attributeName) {
var selector = '[data-' + attributeName + ']';
var eventTarget = event.target;
if (!eventTarget) return;
var target = eventTarget.closest(selector);
if (!target) return;
var categoryAction;
var categoryActionParts;
var options;
categoryAction = target.dataset[toCamelCase(attributeName)];
if (!categoryAction) return;
categoryActionParts = categoryAction.split('|');
options = target.dataset[toCamelCase(trackingOptionsAttributeName)];
options = options ? JSON.parse(options) : {};
self.send_event(
categoryActionParts[0],
categoryActionParts[1],
categoryActionParts[2] || window.location.pathname,
options.service ? { service: options.service } : {}
);
}
function toCamelCase(str) {
return str.replace(/\W+(.)/g, function (match, chr) {
return chr.toUpperCase();
});
};
document.addEventListener('click', function(e) {
handleAction(e, clickTrackingAttributeName);
});
document.addEventListener('submit', function(e) {
handleAction(e, formTrackingAttributeName);
});
},
/**
* @returns {Object[]}
*/
get_data_packets: function get_data_packets() {
return [this.values];
},
/**
* Creates a tracking image for tracking JS compatibility.
*
* @param {string} type The type value for track_js_case in query params for 0.gif
*/
create_tracking_image: function create_tracking_image(type) {
this.send_ping_via_image({
cache_bust: Math.random(),
kind: 'track_js',
track_js_case: type,
});
}
};
return ArchiveAnalytics;
}());
// @license-end

500
Docs/Chapter 1.2 Drawing Graphics_files/banner-styles.css

@ -0,0 +1,500 @@
@import 'record.css'; /* for SPN1 */
#wm-ipp-base {
height:65px;/* initial height just in case js code fails */
padding:0;
margin:0;
border:none;
background:none transparent;
}
#wm-ipp {
z-index: 2147483647;
}
#wm-ipp, #wm-ipp * {
font-family:Lucida Grande, Helvetica, Arial, sans-serif;
font-size:12px;
line-height:1.2;
letter-spacing:0;
width:auto;
height:auto;
max-width:none;
max-height:none;
min-width:0 !important;
min-height:0;
outline:none;
float:none;
text-align:left;
border:none;
color: #000;
text-indent: 0;
position: initial;
background: none;
}
#wm-ipp div, #wm-ipp canvas {
display: block;
}
#wm-ipp div, #wm-ipp tr, #wm-ipp td, #wm-ipp a, #wm-ipp form {
padding:0;
margin:0;
border:none;
border-radius:0;
background-color:transparent;
background-image:none;
/*z-index:2147483640;*/
height:auto;
}
#wm-ipp table {
border:none;
border-collapse:collapse;
margin:0;
padding:0;
width:auto;
font-size:inherit;
}
#wm-ipp form input {
padding:1px !important;
height:auto;
display:inline;
margin:0;
color: #000;
background: none #fff;
border: 1px solid #666;
}
#wm-ipp form input[type=submit] {
padding:0 8px !important;
margin:1px 0 1px 5px !important;
width:auto !important;
border: 1px solid #000 !important;
background: #fff !important;
color: #000 !important;
}
#wm-ipp a {
display: inline;
}
#wm-ipp a:hover{
text-decoration:underline;
}
#wm-ipp a.wm-btn:hover {
text-decoration:none;
color:#ff0 !important;
}
#wm-ipp a.wm-btn:hover span {
color:#ff0 !important;
}
#wm-ipp #wm-ipp-inside {
margin: 0 6px;
border:5px solid #000;
border-top:none;
background-color:rgba(255,255,255,0.9);
-moz-box-shadow:1px 1px 4px #333;
-webkit-box-shadow:1px 1px 4px #333;
box-shadow:1px 1px 4px #333;
border-radius:0 0 8px 8px;
}
/* selectors are intentionally verbose to ensure priority */
#wm-ipp #wm-logo {
padding:0 10px;
vertical-align:middle;
min-width:100px;
flex: 0 0 100px;
}
#wm-ipp .c {
padding-left: 4px;
}
#wm-ipp .c .u {
margin-top: 4px !important;
}
#wm-ipp .n {
padding:0 0 0 5px !important;
vertical-align: bottom;
}
#wm-ipp .n a {
text-decoration:none;
color:#33f;
font-weight:bold;
}
#wm-ipp .n .b {
padding:0 6px 0 0 !important;
text-align:right !important;
overflow:visible;
white-space:nowrap;
color:#99a;
vertical-align:middle;
}
#wm-ipp .n .y .b {
padding:0 6px 2px 0 !important;
}
#wm-ipp .n .c {
background:#000;
color:#ff0;
font-weight:bold;
padding:0 !important;
text-align:center;
}
#wm-ipp.hi .n td.c {
color:#ec008c;
}
#wm-ipp .n td.f {
padding:0 0 0 6px !important;
text-align:left !important;
overflow:visible;
white-space:nowrap;
color:#99a;
vertical-align:middle;
}
#wm-ipp .n tr.m td {
text-transform:uppercase;
white-space:nowrap;
padding:2px 0;
}
#wm-ipp .c .s {
padding:0 5px 0 0 !important;
vertical-align:bottom;
}
#wm-ipp #wm-nav-captures {
white-space: nowrap;
}
#wm-ipp .c .s a.t {
color:#33f;
font-weight:bold;
line-height: 1.8;
}
#wm-ipp .c .s div.r {
color: #666;
font-size:9px;
white-space:nowrap;
}
#wm-ipp .c .k {
padding-bottom:1px;
}
#wm-ipp .c .s {
padding:0 5px 2px 0 !important;
}
#wm-ipp td#displayMonthEl {
padding: 2px 0 !important;
}
#wm-ipp td#displayYearEl {
padding: 0 0 2px 0 !important;
}
div#wm-ipp-sparkline {
position:relative;/* for positioning markers */
white-space:nowrap;
background-color:#fff;
cursor:pointer;
line-height:0.9;
}
#sparklineImgId, #wm-sparkline-canvas {
position:relative;
z-index:9012;
max-width:none;
}
#wm-ipp-sparkline div.yt {
position:absolute;
z-index:9010 !important;
background-color:#ff0 !important;
top: 0;
}
#wm-ipp-sparkline div.mt {
position:absolute;
z-index:9013 !important;
background-color:#ec008c !important;
top: 0;
}
#wm-ipp .r {
margin-left: 4px;
}
#wm-ipp .r a {
color:#33f;
border:none;
position:relative;
background-color:transparent;
background-repeat:no-repeat !important;
background-position:100% 100% !important;
text-decoration: none;
}
#wm-ipp #wm-capinfo {
/* prevents notice div background from sticking into round corners of
#wm-ipp-inside */
border-radius: 0 0 4px 4px;
}
#wm-ipp #wm-capinfo .c-logo {
display:block;
float:left;
margin-right:3px;
width:90px;
min-height:90px;
max-height: 290px;
border-radius:45px;
overflow:hidden;
background-position:50%;
background-size:auto 90px;
box-shadow: 0 0 2px 2px rgba(208,208,208,128) inset;
}
#wm-ipp #wm-capinfo .c-logo span {
display:inline-block;
}
#wm-ipp #wm-capinfo .c-logo img {
height:90px;
position:relative;
left:-50%;
}
#wm-ipp #wm-capinfo .wm-title {
font-size:130%;
}
#wm-ipp #wm-capinfo a.wm-selector {
display:inline-block;
color: #aaa;
text-decoration:none !important;
padding: 2px 8px;
}
#wm-ipp #wm-capinfo a.wm-selector.selected {
background-color:#666;
}
#wm-ipp #wm-capinfo a.wm-selector:hover {
color: #fff;
}
#wm-ipp #wm-capinfo.notice-only #wm-capinfo-collected-by,
#wm-ipp #wm-capinfo.notice-only #wm-capinfo-timestamps {
display: none;
}
#wm-ipp #wm-capinfo #wm-capinfo-notice .wm-capinfo-content {
background-color:#ff0;
padding:5px;
font-size:14px;
text-align:center;
}
#wm-ipp #wm-capinfo #wm-capinfo-notice .wm-capinfo-content * {
font-size:14px;
text-align:center;
}
#wm-ipp #wm-expand {
right: 1px;
bottom: -1px;
color: #ffffff;
background-color: #666 !important;
padding:0 5px 0 3px !important;
border-radius: 3px 3px 0 0 !important;
}
#wm-ipp #wm-expand span {
color: #ffffff;
}
#wm-ipp #wm-expand #wm-expand-icon {
display: inline-block;
transition: transform 0.5s;
transform-origin: 50% 45%;
}
#wm-ipp #wm-expand.wm-open #wm-expand-icon {
transform: rotate(180deg);
}
#wm-ipp #wmtb {
text-align:right;
}
#wm-ipp #wmtb #wmtbURL {
width: calc(100% - 45px);
}
#wm-ipp #wm-graph-anchor {
border-right:1px solid #ccc;
}
/* time coherence */
html.wb-highlight {
box-shadow: inset 0 0 0 3px #a50e3a !important;
}
.wb-highlight {
outline: 3px solid #a50e3a !important;
}
#wm-ipp-print {
display:none !important;
}
@media print {
#wm-ipp-base {
display:none !important;
}
#wm-ipp-print {
display:block !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
@media (max-width:414px) {
#wm-ipp .xxs {
display:none !important;
}
}
@media (min-width:1055px) {
#wm-ipp #wm-graph-anchor {
display:block !important;
}
}
@media (max-width:1054px) {
#wm-ipp #wm-graph-anchor {
display:none !important;
}
}
@media (max-width:1163px) {
#wm-logo {
display:none !important;
}
}
#wm-btns {
white-space: nowrap;
margin-top: -2px;
}
#wm-btns #wm-save-snapshot-open {
margin-right: 7px;
top: -6px;
}
#wm-btns #wm-sign-in {
box-sizing: content-box;
display: none;
margin-right: 7px;
top: -8px;
/*
round border around sign in button
*/
border: 2px #000 solid;
border-radius: 14px;
padding-right: 2px;
padding-bottom: 2px;
width: 11px;
height: 11px;
}
#wm-btns #wm-sign-in>.iconochive-person {
font-size: 12.5px;
}
#wm-save-snapshot-open > .iconochive-web {
color:#000;
font-size:160%;
}
#wm-ipp #wm-share {
display: flex;
align-items: flex-end;
justify-content: space-between;
}
#wm-share > #wm-screenshot {
display: inline-block;
margin-right: 3px;
visibility: hidden;
}
#wm-screenshot > .iconochive-image {
color:#000;
font-size:160%;
}
#wm-share > #wm-video {
display: inline-block;
margin-right: 3px;
visibility: hidden;
}
#wm-video > .iconochive-movies {
color: #000;
display: inline-block;
font-size: 150%;
margin-bottom: 2px;
}
#wm-btns #wm-save-snapshot-in-progress {
display: none;
font-size:160%;
opacity: 0.5;
position: relative;
margin-right: 7px;
top: -5px;
}
#wm-btns #wm-save-snapshot-success {
display: none;
color: green;
position: relative;
top: -7px;
}
#wm-btns #wm-save-snapshot-fail {
display: none;
color: red;
position: relative;
top: -7px;
}
.wm-icon-screen-shot {
background: url("../images/web-screenshot.svg") no-repeat !important;
background-size: contain !important;
width: 22px !important;
height: 19px !important;
display: inline-block;
}
#donato {
/* transition effect is disable so as to simplify height adjustment */
/*transition: height 0.5s;*/
height: 0;
margin: 0;
padding: 0;
border-bottom: 1px solid #999 !important;
}
body.wm-modal {
height: auto !important;
overflow: hidden !important;
}
#donato #donato-base {
width: 100%;
height: 100%;
/*bottom: 0;*/
margin: 0;
padding: 0;
position: absolute;
z-index: 2147483639;
}
body.wm-modal #donato #donato-base {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2147483640;
}
.wb-autocomplete-suggestions {
font-family: Lucida Grande, Helvetica, Arial, sans-serif;
font-size: 12px;
text-align: left;
cursor: default;
border: 1px solid #ccc;
border-top: 0;
background: #fff;
box-shadow: -1px 1px 3px rgba(0,0,0,.1);
position: absolute;
display: none;
z-index: 2147483647;
max-height: 254px;
overflow: hidden;
overflow-y: auto;
box-sizing: border-box;
}
.wb-autocomplete-suggestion {
position: relative;
padding: 0 .6em;
line-height: 23px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.02em;
color: #333;
}
.wb-autocomplete-suggestion b {
font-weight: bold;
}
.wb-autocomplete-suggestion.selected {
background: #f0f0f0;
}

3
Docs/Chapter 1.2 Drawing Graphics_files/bundle-playback.js
File diff suppressed because it is too large
View File

116
Docs/Chapter 1.2 Drawing Graphics_files/iconochive.css

@ -0,0 +1,116 @@
@font-face{font-family:'Iconochive-Regular';src:url('https://archive.org/includes/fonts/Iconochive-Regular.eot?-ccsheb');src:url('https://archive.org/includes/fonts/Iconochive-Regular.eot?#iefix-ccsheb') format('embedded-opentype'),url('https://archive.org/includes/fonts/Iconochive-Regular.woff?-ccsheb') format('woff'),url('https://archive.org/includes/fonts/Iconochive-Regular.ttf?-ccsheb') format('truetype'),url('https://archive.org/includes/fonts/Iconochive-Regular.svg?-ccsheb#Iconochive-Regular') format('svg');font-weight:normal;font-style:normal}
[class^="iconochive-"],[class*=" iconochive-"]{font-family:'Iconochive-Regular'!important;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
.iconochive-Uplevel:before{content:"\21b5"}
.iconochive-exit:before{content:"\1f6a3"}
.iconochive-beta:before{content:"\3b2"}
.iconochive-logo:before{content:"\1f3db"}
.iconochive-audio:before{content:"\1f568"}
.iconochive-movies:before{content:"\1f39e"}
.iconochive-software:before{content:"\1f4be"}
.iconochive-texts:before{content:"\1f56e"}
.iconochive-etree:before{content:"\1f3a4"}
.iconochive-image:before{content:"\1f5bc"}
.iconochive-web:before{content:"\1f5d4"}
.iconochive-collection:before{content:"\2211"}
.iconochive-folder:before{content:"\1f4c2"}
.iconochive-data:before{content:"\1f5c3"}
.iconochive-tv:before{content:"\1f4fa"}
.iconochive-article:before{content:"\1f5cf"}
.iconochive-question:before{content:"\2370"}
.iconochive-question-dark:before{content:"\3f"}
.iconochive-info:before{content:"\69"}
.iconochive-info-small:before{content:"\24d8"}
.iconochive-comment:before{content:"\1f5e9"}
.iconochive-comments:before{content:"\1f5ea"}
.iconochive-person:before{content:"\1f464"}
.iconochive-people:before{content:"\1f465"}
.iconochive-eye:before{content:"\1f441"}
.iconochive-rss:before{content:"\221e"}
.iconochive-time:before{content:"\1f551"}
.iconochive-quote:before{content:"\275d"}
.iconochive-disc:before{content:"\1f4bf"}
.iconochive-tv-commercial:before{content:"\1f4b0"}
.iconochive-search:before{content:"\1f50d"}
.iconochive-search-star:before{content:"\273d"}
.iconochive-tiles:before{content:"\229e"}
.iconochive-list:before{content:"\21f6"}
.iconochive-list-bulleted:before{content:"\2317"}
.iconochive-latest:before{content:"\2208"}
.iconochive-left:before{content:"\2c2"}
.iconochive-right:before{content:"\2c3"}
.iconochive-left-solid:before{content:"\25c2"}
.iconochive-right-solid:before{content:"\25b8"}
.iconochive-up-solid:before{content:"\25b4"}
.iconochive-down-solid:before{content:"\25be"}
.iconochive-dot:before{content:"\23e4"}
.iconochive-dots:before{content:"\25a6"}
.iconochive-columns:before{content:"\25af"}
.iconochive-sort:before{content:"\21d5"}
.iconochive-atoz:before{content:"\1f524"}
.iconochive-ztoa:before{content:"\1f525"}
.iconochive-upload:before{content:"\1f4e4"}
.iconochive-download:before{content:"\1f4e5"}
.iconochive-favorite:before{content:"\2605"}
.iconochive-heart:before{content:"\2665"}
.iconochive-play:before{content:"\25b6"}
.iconochive-play-framed:before{content:"\1f3ac"}
.iconochive-fullscreen:before{content:"\26f6"}
.iconochive-mute:before{content:"\1f507"}
.iconochive-unmute:before{content:"\1f50a"}
.iconochive-share:before{content:"\1f381"}
.iconochive-edit:before{content:"\270e"}
.iconochive-reedit:before{content:"\2710"}
.iconochive-gear:before{content:"\2699"}
.iconochive-remove-circle:before{content:"\274e"}
.iconochive-plus-circle:before{content:"\1f5d6"}
.iconochive-minus-circle:before{content:"\1f5d5"}
.iconochive-x:before{content:"\1f5d9"}
.iconochive-fork:before{content:"\22d4"}
.iconochive-trash:before{content:"\1f5d1"}
.iconochive-warning:before{content:"\26a0"}
.iconochive-flash:before{content:"\1f5f2"}
.iconochive-world:before{content:"\1f5fa"}
.iconochive-lock:before{content:"\1f512"}
.iconochive-unlock:before{content:"\1f513"}
.iconochive-twitter:before{content:"\1f426"}
.iconochive-facebook:before{content:"\66"}
.iconochive-googleplus:before{content:"\67"}
.iconochive-reddit:before{content:"\1f47d"}
.iconochive-tumblr:before{content:"\54"}
.iconochive-pinterest:before{content:"\1d4df"}
.iconochive-popcorn:before{content:"\1f4a5"}
.iconochive-email:before{content:"\1f4e7"}
.iconochive-embed:before{content:"\1f517"}
.iconochive-gamepad:before{content:"\1f579"}
.iconochive-Zoom_In:before{content:"\2b"}
.iconochive-Zoom_Out:before{content:"\2d"}
.iconochive-RSS:before{content:"\1f4e8"}
.iconochive-Light_Bulb:before{content:"\1f4a1"}
.iconochive-Add:before{content:"\2295"}
.iconochive-Tab_Activity:before{content:"\2318"}
.iconochive-Forward:before{content:"\23e9"}
.iconochive-Backward:before{content:"\23ea"}
.iconochive-No_Audio:before{content:"\1f508"}
.iconochive-Pause:before{content:"\23f8"}
.iconochive-No_Favorite:before{content:"\2606"}
.iconochive-Unike:before{content:"\2661"}
.iconochive-Song:before{content:"\266b"}
.iconochive-No_Flag:before{content:"\2690"}
.iconochive-Flag:before{content:"\2691"}
.iconochive-Done:before{content:"\2713"}
.iconochive-Check:before{content:"\2714"}
.iconochive-Refresh:before{content:"\27f3"}
.iconochive-Headphones:before{content:"\1f3a7"}
.iconochive-Chart:before{content:"\1f4c8"}
.iconochive-Bookmark:before{content:"\1f4d1"}
.iconochive-Documents:before{content:"\1f4da"}
.iconochive-Newspaper:before{content:"\1f4f0"}
.iconochive-Podcast:before{content:"\1f4f6"}
.iconochive-Radio:before{content:"\1f4fb"}
.iconochive-Cassette:before{content:"\1f4fc"}
.iconochive-Shuffle:before{content:"\1f500"}
.iconochive-Loop:before{content:"\1f501"}
.iconochive-Low_Audio:before{content:"\1f509"}
.iconochive-First:before{content:"\1f396"}
.iconochive-Invisible:before{content:"\1f576"}
.iconochive-Computer:before{content:"\1f5b3"}

876
Docs/Chapter 1.2 Drawing Graphics_files/ordertable-buffercompare.svg

@ -0,0 +1,876 @@
<?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="430"
height="260"
viewBox="0 0 113.77083 68.79167"
version="1.1"
id="svg8"
sodipodi:docname="ordertable-buffercompare.svg"
inkscape:version="0.92.1 r15371">
<defs
id="defs2">
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="marker8518"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8516"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="marker8376"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8374"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8306"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM"
inkscape:collect="always">
<path
transform="scale(0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8304"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8296"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
transform="scale(0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8294"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker8220"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutM">
<path
transform="scale(0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path8218"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="TriangleOutM"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path7287"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0"
refX="0"
id="marker8024"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8022"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker7876"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleOutS">
<path
transform="scale(0.2)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path7874"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker7696"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path7694"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker7578"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path7576"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker7096"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
inkscape:connector-curvature="0"
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path7094" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6521"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path6519"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6517"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path6515"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6513"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path6511"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9871"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9806"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9804"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker6984"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6982"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5944"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path5942"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5328"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5326" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5883"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5881"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5705"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5703"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4561"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4570"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="79.63324"
inkscape:cy="106.88666"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:snap-bbox="false"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-nodes="true"
inkscape:snap-others="true"
inkscape:object-nodes="true"
inkscape:snap-midpoints="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:bbox-nodes="false"
inkscape:object-paths="true"
inkscape:snap-global="true"
inkscape:snap-text-baseline="true"
showguides="true"
inkscape:guide-bbox="true">
<sodipodi:guide
position="0,0"
orientation="0,512"
id="guide4485"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,0"
orientation="-512,0"
id="guide4487"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,135.46666"
orientation="0,-512"
id="guide4489"
inkscape:locked="false" />
<sodipodi:guide
position="0,135.46666"
orientation="512,0"
id="guide4491"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid5858" />
<sodipodi:guide
position="88.635414,66.145836"
orientation="1,0"
id="guide6770"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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(0,-228.20831)">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="48.947918"
height="3.9687502"
x="5.2916665"
y="234.82289" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="29.104166"
y="237.46872"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="29.104166"
y="237.46872"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Process graphics to OT</tspan></text>
<text
id="text5550"
y="242.76039"
x="29.104168"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="242.76039"
x="29.104168"
id="tspan5548"
sodipodi:role="line">OT sent to GPU</tspan></text>
<text
id="text4576"
y="237.46872"
x="88.635414"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="237.46872"
x="88.635414"
id="tspan4574"
sodipodi:role="line">GPU idle</tspan></text>
<flowRoot
xml:space="preserve"
id="flowRoot4578"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
transform="matrix(0.26458333,0,0,0.26458333,1.5894572e-7,246.72913)"><flowRegion
id="flowRegion4580"><rect
id="rect4582"
width="209.5"
height="83.5"
x="234.5"
y="-44" /></flowRegion><flowPara
id="flowPara4584" /></flowRoot> <text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="88.635414"
y="242.76039"
id="text4590"><tspan
sodipodi:role="line"
id="tspan4588"
x="88.635414"
y="242.76039"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">GPU busy</tspan></text>
<text
id="text4596"
y="248.05206"
x="29.104166"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="248.05206"
x="29.104166"
id="tspan4594"
sodipodi:role="line">Process graphics to OT</tspan></text>
<text
id="text4602"
y="248.05206"
x="88.635414"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="248.05206"
x="88.635414"
id="tspan4600"
sodipodi:role="line">GPU busy</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="29.104168"
y="258.63541"
id="text4608"><tspan
sodipodi:role="line"
id="tspan4606"
x="29.104168"
y="258.63541"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT sent to GPU</tspan></text>
<text
id="text4614"
y="258.63541"
x="88.635414"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="258.63541"
x="88.635414"
id="tspan4612"
sodipodi:role="line">GPU busy</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker8376);paint-order:normal"
d="m 54.239583,241.96664 h 7.9375"
id="path4640"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker8518);paint-order:normal"
d="m 54.239583,257.84164 h 7.9375"
id="path4642"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="29.104168"
y="253.34372"
id="text4650"><tspan
sodipodi:role="line"
id="tspan4648"
x="29.104168"
y="253.34372"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Wait for GPU (DrawSync())</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="88.635414"
y="253.34372"
id="text4656"><tspan
sodipodi:role="line"
id="tspan4654"
x="88.635414"
y="253.34372"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">GPU finished</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker8306);paint-order:normal"
d="M 5.2916669,257.84164 H 1.5875 L 1.3229167,257.57706 V 247.52289 L 1.5875,247.25831 h 2.3812502"
id="path4658"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<text
id="text5925"
y="271.86456"
x="29.104166"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="271.86456"
x="29.104166"
id="tspan5923"
sodipodi:role="line">Process graphics to OT</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="88.635414"
y="271.86456"
id="text5931"><tspan
sodipodi:role="line"
id="tspan5929"
x="88.635414"
y="271.86456"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">GPU idle</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="29.104168"
y="277.15625"
id="text5937"><tspan
sodipodi:role="line"
id="tspan5935"
x="29.104168"
y="277.15625"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT sent to GPU</tspan></text>
<text
id="text5943"
y="277.15625"
x="88.635414"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="277.15625"
x="88.635414"
id="tspan5941"
sodipodi:role="line">GPU busy</tspan></text>
<path
inkscape:connector-curvature="0"
id="path5945"
d="m 54.239583,276.36248 h 7.927435"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#TriangleOutM);paint-order:normal"
sodipodi:nodetypes="cc" />
<text
id="text5951"
y="282.44791"
x="29.104168"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="282.44791"
x="29.104168"
id="tspan5949"
sodipodi:role="line">Wait for GPU (DrawSync())</tspan></text>
<text
id="text5957"
y="282.44791"
x="88.635414"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="282.44791"
x="88.635414"
id="tspan5955"
sodipodi:role="line">GPU finished</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="88.635414"
y="287.73956"
id="text5963"><tspan
sodipodi:role="line"
id="tspan5961"
x="88.635414"
y="287.73956"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">GPU idle</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="29.104166"
y="287.73956"
id="text5969"><tspan
sodipodi:role="line"
id="tspan5967"
x="29.104166"
y="287.73956"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Process graphics to OT</tspan></text>
<text
id="text5975"
y="293.03125"
x="29.104168"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="293.03125"
x="29.104168"
id="tspan5973"
sodipodi:role="line">OT sent to GPU</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="88.635414"
y="293.03125"
id="text5981"><tspan
sodipodi:role="line"
id="tspan5979"
x="88.635414"
y="293.03125"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">GPU busy</tspan></text>
<path
inkscape:connector-curvature="0"
id="path5983"
d="m 54.239583,292.23748 h 7.927435"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker8220);paint-order:normal"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path6151"
d="M 5.2916669,292.23748 H 1.8520834 l -0.5291667,-0.52917 v -9.525 l 0.5291667,-0.52917 h 2.1166668"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker8296);paint-order:normal" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="1.3229167"
y="266.57291"
id="text9977"><tspan
sodipodi:role="line"
id="tspan9975"
x="1.3229167"
y="266.57291"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26499999">Single OT+Prim. Buffer</tspan></text>
<text
id="text9981"
y="232.17706"
x="1.3229167"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26499999"
y="232.17706"
x="1.3229167"
id="tspan9979"
sodipodi:role="line">Double OT+Prim. Buffer</tspan></text>
<rect
y="240.11456"
x="5.2916665"
height="3.9687502"
width="48.947918"
id="rect5860"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5862"
width="48.947918"
height="3.9687502"
x="5.2916665"
y="245.40622" />
<rect
y="250.69789"
x="5.2916665"
height="3.9687502"
width="48.947918"
id="rect5864"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5866"
width="48.947918"
height="3.9687502"
x="5.2916665"
y="255.98956" />
<rect
y="234.82289"
x="63.5"
height="3.9687502"
width="48.947918"
id="rect5868"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5870"
width="48.947918"
height="3.9687502"
x="63.5"
y="240.11456" />
<rect
y="245.40622"
x="63.5"
height="3.9687502"
width="48.947918"
id="rect5872"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5874"
width="48.947918"
height="3.9687502"
x="63.5"
y="250.69789" />
<rect
y="255.98956"
x="63.5"
height="3.9687502"
width="48.947918"
id="rect5876"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
y="269.21875"
x="5.2916665"
height="3.9687502"
width="48.947918"
id="rect6520"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect6522"
width="48.947918"
height="3.9687502"
x="5.2916656"
y="274.51041" />
<rect
y="279.80206"
x="5.2916665"
height="3.9687502"
width="48.947918"
id="rect6524"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect6526"
width="48.947918"
height="3.9687502"
x="5.2916665"
y="285.09375" />
<rect
y="290.38541"
x="5.2916665"
height="3.9687502"
width="48.947918"
id="rect6528"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect6772"
width="48.947918"
height="3.9687502"
x="63.5"
y="269.21875" />
<rect
y="274.51041"
x="63.499996"
height="3.9687502"
width="48.947918"
id="rect6774"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect6776"
width="48.947918"
height="3.9687502"
x="63.5"
y="279.80206" />
<rect
y="285.09375"
x="63.5"
height="3.9687502"
width="48.947918"
id="rect6778"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect6780"
width="48.947918"
height="3.9687502"
x="63.5"
y="290.38541" />
</g>
</svg>

705
Docs/Chapter 1.2 Drawing Graphics_files/ordertable-multiprims.svg

@ -0,0 +1,705 @@
<?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="420"
height="220"
viewBox="0 0 111.125 58.208337"
version="1.1"
id="svg8"
sodipodi:docname="ordertable-multiprims.svg"
inkscape:version="0.92.1 r15371">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker7807"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path7805" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker7561"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path7559"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6581"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path6579" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6049"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path6047" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5905"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path5903" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9889"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9871"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9806"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9804"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker6984"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6982"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5944"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path5942"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5328"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5326" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5883"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5881"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5705"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5703"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4561"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4570"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4984"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4982"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker13622"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path13620"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4575"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4573"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4587"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4585"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4593"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4591"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4599"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4597"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4605"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4603"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="298.22087"
inkscape:cy="212.17404"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="false"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-nodes="true"
inkscape:snap-others="true"
inkscape:object-nodes="true"
inkscape:snap-midpoints="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:bbox-nodes="false"
inkscape:object-paths="true"
inkscape:snap-global="true"
inkscape:snap-text-baseline="true">
<sodipodi:guide
position="0,0"
orientation="0,512"
id="guide4485"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,0"
orientation="-512,0"
id="guide4487"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,135.46666"
orientation="0,-512"
id="guide4489"
inkscape:locked="false" />
<sodipodi:guide
position="0,135.46666"
orientation="512,0"
id="guide4491"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid5333" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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(0,-238.79163)">
<text
id="text7984"
y="267.10205"
x="85.989586"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="267.10205"
x="85.989586"
id="tspan7982"
sodipodi:role="line">Primitive 2</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="48.947918"
height="5.2916636"
x="6.6145835"
y="240.1145" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="244.08325"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="31.750002"
y="244.08325"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[0]=0xffffffff (end)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="295.67703"
id="text4545"><tspan
sodipodi:role="line"
id="tspan4543"
x="31.750002"
y="295.67703"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Start of table</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4984);paint-order:normal"
d="m 5.5562491,242.76034 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
id="path4553"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<rect
y="246.72908"
x="6.6145835"
height="5.2916694"
width="48.947918"
id="rect5546"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5550"
y="250.69783"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="250.69783"
x="31.750002"
id="tspan5548"
sodipodi:role="line">OT[1]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5576"
width="48.947918"
height="5.2916741"
x="6.6145835"
y="253.34367" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="257.31244"
id="text5580"><tspan
sodipodi:role="line"
id="tspan5578"
x="31.750002"
y="257.31244"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[2]</tspan></text>
<rect
y="259.95831"
x="6.6145835"
height="5.2916636"
width="48.947918"
id="rect5582"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5586"
y="263.92706"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="263.92706"
x="31.750002"
id="tspan5584"
sodipodi:role="line">OT[3]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5588"
width="48.947918"
height="5.2916536"
x="6.6145835"
y="266.57288" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="270.54163"
id="text5592"><tspan
sodipodi:role="line"
id="tspan5590"
x="31.750002"
y="270.54163"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[4]</tspan></text>
<rect
y="273.18747"
x="6.6145835"
height="5.2916741"
width="48.947918"
id="rect5594"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5598"
y="277.15622"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="277.15622"
x="31.750002"
id="tspan5596"
sodipodi:role="line">OT[5]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5600"
width="48.947918"
height="5.2916636"
x="6.6145835"
y="279.80203" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="283.77078"
id="text5604"><tspan
sodipodi:role="line"
id="tspan5602"
x="31.750002"
y="283.77078"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[6]</tspan></text>
<rect
y="286.41666"
x="6.6145835"
height="5.2916536"
width="48.947918"
id="rect5606"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5610"
y="290.38541"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="290.38541"
x="31.750002"
id="tspan5608"
sodipodi:role="line">OT[7]</tspan></text>
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path13452"
d="m 56.620832,249.37492 2.381253,1e-5 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 h -3.439586"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker13622);paint-order:normal" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4571"
d="m 5.5562491,255.98951 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4575);paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4587);paint-order:normal"
d="m 5.5562491,269.21868 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
id="path4583"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4589"
d="m 56.620832,275.83325 2.381253,10e-6 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 h -3.439586"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4593);paint-order:normal" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4595"
d="m 5.5562491,282.44784 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4599);paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4605);paint-order:normal"
d="m 56.620832,289.06242 2.381253,1e-5 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 4.23333 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 H 42.333332"
id="path4601"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<rect
y="263.39789"
x="68.791664"
height="5.2916584"
width="35.718754"
id="rect5707"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker6049);paint-order:normal"
d="m 67.733333,272.39371 h -5.55625 c -1.852082,0 -0.529166,-3.17499 -2.645833,-3.17499 h -3.968751"
id="path6033"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker6581);paint-order:normal"
d="m 56.620833,262.60413 h 2.910416 c 2.116668,0 0.529165,-7.9375 2.645831,-7.9375 h 44.97917 c 0.79375,0 1.32292,0.52917 1.32292,1.32292 l 0,2.11666 c 0,0.79375 -0.52917,1.32292 -1.30202,1.32292 h -2.66673"
id="path6571"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect7433"
width="35.718754"
height="5.2916689"
x="68.791664"
y="256.78329" />
<rect
y="270.01245"
x="68.791664"
height="5.2916789"
width="35.718754"
id="rect7435"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker7561);paint-order:normal"
d="m 105.56875,266.04371 2.38126,1e-5 c 0.26458,0 0.52916,0.26458 0.52916,0.52917 v 5.55625 c 0,0.26458 -0.26458,0.52916 -0.52916,0.52916 h -3.43959"
id="path7557"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path7803"
d="m 67.733333,259.42913 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker7807);paint-order:normal" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="85.989586"
y="260.48746"
id="text8261"><tspan
sodipodi:role="line"
id="tspan8259"
x="85.989586"
y="260.48746"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Primitive 1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="85.989586"
y="273.71664"
id="text8265"><tspan
sodipodi:role="line"
id="tspan8263"
x="85.989586"
y="273.71664"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Primitive 3</tspan></text>
</g>
</svg>

657
Docs/Chapter 1.2 Drawing Graphics_files/ordertable-primitive.svg

@ -0,0 +1,657 @@
<?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="420"
height="220"
viewBox="0 0 111.125 58.208337"
version="1.1"
id="svg8"
sodipodi:docname="ordertable-primitive.svg"
inkscape:version="0.92.1 r15371">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker7807"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path7805" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker7561"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path7559"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6581"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path6579" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6049"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path6047" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5905"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path5903" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9889"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9871"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9806"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9804"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker6984"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6982"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5944"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path5942"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5328"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5326" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5883"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5881"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5705"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5703"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4561"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4570"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4984"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4982"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker13622"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path13620"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4575"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4573"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4587"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4585"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4593"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4591"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4599"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4597"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4605"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4603"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="6.8701326"
inkscape:cx="331.92997"
inkscape:cy="122.79977"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:snap-bbox="false"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-nodes="true"
inkscape:snap-others="true"
inkscape:object-nodes="true"
inkscape:snap-midpoints="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:bbox-nodes="false"
inkscape:object-paths="true"
inkscape:snap-global="true"
inkscape:snap-text-baseline="true">
<sodipodi:guide
position="0,0"
orientation="0,512"
id="guide4485"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,0"
orientation="-512,0"
id="guide4487"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,135.46666"
orientation="0,-512"
id="guide4489"
inkscape:locked="false" />
<sodipodi:guide
position="0,135.46666"
orientation="512,0"
id="guide4491"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid5333" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-238.79163)">
<text
id="text7984"
y="267.10205"
x="85.989586"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="267.10205"
x="85.989586"
id="tspan7982"
sodipodi:role="line">Primitive</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="48.947918"
height="5.2916636"
x="6.6145835"
y="240.1145" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="244.08325"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="31.750002"
y="244.08325"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[0]=0xffffffff (end)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="295.67703"
id="text4545"><tspan
sodipodi:role="line"
id="tspan4543"
x="31.750002"
y="295.67703"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Start of table</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4984);paint-order:normal"
d="m 5.5562491,242.76034 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
id="path4553"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<rect
y="246.72908"
x="6.6145835"
height="5.2916694"
width="48.947918"
id="rect5546"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5550"
y="250.69783"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="250.69783"
x="31.750002"
id="tspan5548"
sodipodi:role="line">OT[1]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5576"
width="48.947918"
height="5.2916741"
x="6.6145835"
y="253.34367" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="257.31244"
id="text5580"><tspan
sodipodi:role="line"
id="tspan5578"
x="31.750002"
y="257.31244"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[2]</tspan></text>
<rect
y="259.95831"
x="6.6145835"
height="5.2916636"
width="48.947918"
id="rect5582"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5586"
y="263.92706"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="263.92706"
x="31.750002"
id="tspan5584"
sodipodi:role="line">OT[3]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5588"
width="48.947918"
height="5.2916536"
x="6.6145835"
y="266.57288" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="270.54163"
id="text5592"><tspan
sodipodi:role="line"
id="tspan5590"
x="31.750002"
y="270.54163"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[4]</tspan></text>
<rect
y="273.18747"
x="6.6145835"
height="5.2916741"
width="48.947918"
id="rect5594"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5598"
y="277.15622"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="277.15622"
x="31.750002"
id="tspan5596"
sodipodi:role="line">OT[5]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5600"
width="48.947918"
height="5.2916636"
x="6.6145835"
y="279.80203" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="283.77078"
id="text5604"><tspan
sodipodi:role="line"
id="tspan5602"
x="31.750002"
y="283.77078"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[6]</tspan></text>
<rect
y="286.41666"
x="6.6145835"
height="5.2916536"
width="48.947918"
id="rect5606"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5610"
y="290.38541"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="290.38541"
x="31.750002"
id="tspan5608"
sodipodi:role="line">OT[7]</tspan></text>
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path13452"
d="m 56.620832,249.37492 2.381253,1e-5 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 h -3.439586"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker13622);paint-order:normal" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4571"
d="m 5.5562491,255.98951 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4575);paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4587);paint-order:normal"
d="m 5.5562491,269.21868 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
id="path4583"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4589"
d="m 56.620832,275.83325 2.381253,10e-6 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 h -3.439586"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4593);paint-order:normal" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4595"
d="m 5.5562491,282.44784 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4599);paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4605);paint-order:normal"
d="m 56.620832,289.06242 2.381253,1e-5 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 4.23333 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 H 42.333332"
id="path4601"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<rect
y="263.39789"
x="68.791664"
height="5.2916584"
width="35.718754"
id="rect5707"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker6049);paint-order:normal"
d="m 67.733334,266.04372 h -5.55625 c -1.852082,0 -0.529166,3.17499 -2.645833,3.17499 H 55.5625"
id="path6033"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker6581);paint-order:normal"
d="m 56.620833,262.60413 h 2.910416 c 2.116668,0 0.529162,-2.64584 2.645828,-2.64584 h 44.979173 c 0.79375,0 1.32292,0.52917 1.32292,1.32292 v 3.43958 c 0,0.79375 -0.52917,1.32292 -1.30202,1.32292 h -2.66673"
id="path6571"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

633
Docs/Chapter 1.2 Drawing Graphics_files/ordertable.svg

@ -0,0 +1,633 @@
<?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="235"
height="220"
viewBox="0 0 62.177082 58.208337"
version="1.1"
id="svg8"
sodipodi:docname="ordertable.svg"
inkscape:version="0.92.1 r15371">
<defs
id="defs2">
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4605"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4603"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4599"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4597"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4593"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4591"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4587"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4585"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4581"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4579"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4575"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4573"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker13622"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path13620"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4984"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4982"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInL"
orient="auto"
refY="0"
refX="0"
id="TriangleInL"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4691"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.8)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="TriangleInM"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4694"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4576"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(1.1,0,0,1.1,1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4558"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4582"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Sstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Sstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4588"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(0.3,0,0,0.3,-0.69,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker7236"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path7234" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker6984"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6982"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5944"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path5942"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5328"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5326" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5883"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5881"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5705"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5703"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4561"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4570"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="72.018278"
inkscape:cy="110.6517"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:snap-bbox="false"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-nodes="true"
inkscape:snap-others="true"
inkscape:object-nodes="true"
inkscape:snap-midpoints="false"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:bbox-nodes="false"
inkscape:object-paths="false"
inkscape:snap-global="true"
inkscape:snap-text-baseline="true"
inkscape:snap-smooth-nodes="false">
<sodipodi:guide
position="0,0"
orientation="0,512"
id="guide4485"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,0"
orientation="-512,0"
id="guide4487"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,135.46666"
orientation="0,-512"
id="guide4489"
inkscape:locked="false" />
<sodipodi:guide
position="0,135.46666"
orientation="512,0"
id="guide4491"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid4556" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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(0,-238.79163)">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="48.947918"
height="5.2916636"
x="6.6145835"
y="240.11455" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="244.0833"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="31.750002"
y="244.0833"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[0]=0xffffffff (end)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="295.67703"
id="text4545"><tspan
sodipodi:role="line"
id="tspan4543"
x="31.750002"
y="295.67703"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Start of table</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4984);paint-order:normal"
d="m 5.5562498,242.76037 h -2.38125 c -0.2645834,0 -0.5291667,0.26458 -0.5291667,0.52917 v 5.55625 c 0,0.26458 0.2645833,0.52916 0.5291667,0.52916 h 3.4395833"
id="path4553"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<rect
y="246.72913"
x="6.6145835"
height="5.2916689"
width="48.947918"
id="rect5546"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5550"
y="250.69788"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="250.69788"
x="31.750002"
id="tspan5548"
sodipodi:role="line">OT[1]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5576"
width="48.947918"
height="5.2916741"
x="6.6145835"
y="253.3437" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="257.31244"
id="text5580"><tspan
sodipodi:role="line"
id="tspan5578"
x="31.750002"
y="257.31244"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[2]</tspan></text>
<rect
y="259.95828"
x="6.6145835"
height="5.2916636"
width="48.947918"
id="rect5582"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5586"
y="263.92703"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="263.92703"
x="31.750002"
id="tspan5584"
sodipodi:role="line">OT[3]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5588"
width="48.947918"
height="5.2916536"
x="6.6145835"
y="266.57288" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="270.54163"
id="text5592"><tspan
sodipodi:role="line"
id="tspan5590"
x="31.750002"
y="270.54163"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[4]</tspan></text>
<rect
y="273.18744"
x="6.6145835"
height="5.2916741"
width="48.947918"
id="rect5594"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5598"
y="277.15619"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="277.15619"
x="31.750002"
id="tspan5596"
sodipodi:role="line">OT[5]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5600"
width="48.947918"
height="5.2916636"
x="6.6145835"
y="279.80203" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="283.77078"
id="text5604"><tspan
sodipodi:role="line"
id="tspan5602"
x="31.750002"
y="283.77078"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[6]</tspan></text>
<rect
y="286.41663"
x="6.6145835"
height="5.2916536"
width="48.947918"
id="rect5606"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5610"
y="290.38538"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="290.38538"
x="31.750002"
id="tspan5608"
sodipodi:role="line">OT[7]</tspan></text>
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path13452"
d="m 56.620833,249.37495 2.381251,10e-6 c 0.264583,0 0.529166,0.26458 0.529166,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529166,0.52916 H 55.5625"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker13622);paint-order:normal" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4571"
d="m 5.5562498,255.98954 h -2.38125 c -0.2645834,0 -0.5291667,0.26458 -0.5291667,0.52917 v 5.55625 c 0,0.26458 0.2645833,0.52916 0.5291667,0.52916 h 3.4395833"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4575);paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4581);paint-order:normal"
d="m 56.620833,262.60411 2.381251,1e-5 c 0.264583,0 0.529166,0.26458 0.529166,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529166,0.52916 H 55.5625"
id="path4577"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4587);paint-order:normal"
d="m 5.5562498,269.21871 h -2.38125 c -0.2645834,0 -0.5291667,0.26458 -0.5291667,0.52917 v 5.55625 c 0,0.26458 0.2645833,0.52916 0.5291667,0.52916 h 3.4395833"
id="path4583"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4589"
d="m 56.620833,275.83328 2.381251,10e-6 c 0.264583,0 0.529166,0.26458 0.529166,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529166,0.52916 H 55.5625"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4593);paint-order:normal" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4595"
d="m 5.5562498,282.44787 h -2.38125 c -0.2645834,0 -0.5291667,0.26458 -0.5291667,0.52917 v 5.55625 c 0,0.26458 0.2645833,0.52916 0.5291667,0.52916 h 3.4395833"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4599);paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4605);paint-order:normal"
d="m 56.620833,289.06245 2.381251,10e-6 c 0.264583,0 0.529166,0.26458 0.529166,0.52917 v 4.23333 c 0,0.26458 -0.264583,0.52916 -0.529166,0.52916 H 42.333333"
id="path4601"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
</g>
</svg>

350
Docs/Chapter 1.2 Drawing Graphics_files/primstruct.svg

@ -0,0 +1,350 @@
<?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="210"
height="120"
viewBox="0 0 55.562499 31.750002"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="primstruct.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="86.433235"
inkscape:cy="88.08852"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:snap-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-text-baseline="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-intersection-paths="true"
showborder="true">
<sodipodi:guide
position="0,0"
orientation="0,300"
id="guide4618"
inkscape:locked="false" />
<sodipodi:guide
position="79.375,0"
orientation="-200,0"
id="guide4620"
inkscape:locked="false" />
<sodipodi:guide
position="79.375,52.916667"
orientation="0,-300"
id="guide4622"
inkscape:locked="false" />
<sodipodi:guide
position="0,52.916667"
orientation="200,0"
id="guide4624"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid4537" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-265.24996)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="47.625"
y="267.89578"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="47.625"
y="267.89578"
style="text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332">31</tspan></text>
<text
id="text4501"
y="267.89578"
x="2.6458333"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="267.89578"
x="2.6458333"
id="tspan4499"
sodipodi:role="line">0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="19.84375"
y="273.18747"
id="text4534"><tspan
sodipodi:role="line"
id="tspan4532"
x="19.84375"
y="273.18747"
style="text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Next Pointer</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="44.979168"
y="273.18747"
id="text4538"><tspan
sodipodi:role="line"
id="tspan4536"
x="44.979168"
y="273.18747"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">Len</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="7.7092853"
y="278.45084"
id="text4542"><tspan
sodipodi:role="line"
id="tspan4540"
x="7.7092853"
y="278.45084"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">R</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="20.372917"
y="278.47913"
id="text4546"><tspan
sodipodi:role="line"
id="tspan4544"
x="20.372917"
y="278.47913"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">G</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="32.279167"
y="278.47913"
id="text4550"><tspan
sodipodi:role="line"
id="tspan4548"
x="32.279167"
y="278.47913"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">B</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="44.979168"
y="278.47913"
id="text4554"><tspan
sodipodi:role="line"
id="tspan4552"
x="44.979168"
y="278.47913"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">Code</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="14.552083"
y="283.77078"
id="text4558"><tspan
sodipodi:role="line"
id="tspan4556"
x="14.552083"
y="283.77078"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">X</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="39.6875"
y="283.77078"
id="text4562"><tspan
sodipodi:role="line"
id="tspan4560"
x="39.6875"
y="283.77078"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">Y</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="7.9375"
y="289.06247"
id="text4566"><tspan
sodipodi:role="line"
id="tspan4564"
x="7.9375"
y="289.06247"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">U</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="21.166666"
y="289.06247"
id="text4570"><tspan
sodipodi:role="line"
id="tspan4568"
x="21.166666"
y="289.06247"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">V</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="39.6875"
y="289.06247"
id="text4574"><tspan
sodipodi:role="line"
id="tspan4572"
x="39.6875"
y="289.06247"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">CLUT</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="14.552083"
y="294.35413"
id="text4582"><tspan
sodipodi:role="line"
id="tspan4580"
x="14.552083"
y="294.35413"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">Width</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:start;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="39.6875"
y="294.35413"
id="text4586"><tspan
sodipodi:role="line"
id="tspan4584"
x="39.6875"
y="294.35413"
style="text-align:center;text-anchor:middle;stroke-width:0.26458332">Height</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4590"
width="25.135416"
height="5.2916675"
x="1.3229166"
y="290.38538" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4592"
width="25.135416"
height="5.2916675"
x="26.458334"
y="290.38538" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4594"
width="13.229167"
height="5.2524114"
x="1.3229166"
y="285.13297" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4598"
width="25.135416"
height="5.291657"
x="26.458334"
y="285.09372" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4600"
width="25.135416"
height="5.2916775"
x="26.458334"
y="279.80203" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4602"
width="25.135416"
height="5.2916775"
x="1.3229166"
y="279.80203" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4604"
width="13.229167"
height="5.2916675"
x="1.3229166"
y="274.51038" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4606"
width="11.90625"
height="5.2916675"
x="14.552083"
y="274.51038" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4608"
width="11.906249"
height="5.2916675"
x="26.458334"
y="274.51038" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4610"
width="13.229168"
height="5.2916675"
x="38.364582"
y="274.51038" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4612"
width="13.229168"
height="5.291657"
x="38.364582"
y="269.21872" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4614"
width="37.041668"
height="5.291657"
x="1.3229166"
y="269.21872" />
<rect
y="285.09372"
x="14.552083"
height="5.291657"
width="11.90625"
id="rect4616"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
y="274.51038"
x="26.458334"
height="5.2916675"
width="11.906249"
id="rect4539"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.396875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
</g>
</svg>

70
Docs/Chapter 1.2 Drawing Graphics_files/style.css

@ -0,0 +1,70 @@
body {
max-width: 900px;
margin: auto;
padding: 8px;
font-family: sans-serif;
font-size: 14px;
//color: white;
//background: black;
}
h {
background-color: #e0e0e0;
padding: 2px;
}
h2 {
border-bottom: 1px solid;
//padding-left: 8px;
}
img {
display: block;
}
.footer-table {
font-size: 14px;
}
.bordered-table {
border-collapse: collapse;
font-size: 11px;
}
.bordered-table th, .bordered-table td {
border: 1px solid;
padding: 4px;
}
hr {
border: none;
border-bottom: 1px solid black;
}
pre {
padding: 8px;
font-size: 12px;
color: black;
background-color: LightGray;
}
/*
FILE ARCHIVED ON 03:35:25 Aug 27, 2022 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 15:39:09 Sep 05, 2022.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
*/
/*
playback timings (ms):
captures_list: 107.165
exclusion.robots: 0.073
exclusion.robots.policy: 0.067
cdx.remote: 0.064
esindex: 0.009
LoadShardBlock: 52.713 (3)
PetaboxLoader3.datanode: 140.466 (4)
CDXLines.iter: 14.771 (3)
load_resource: 139.896
PetaboxLoader3.resolve: 47.824
*/

21
Docs/Chapter 1.2 Drawing Graphics_files/wombat.js
File diff suppressed because it is too large
View File

919
Docs/Chapter 1.3 Textures, TPages and CLUTs.htm

@ -0,0 +1,919 @@
<html><head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="Chapter%201.3%20Textures,%20TPages%20and%20CLUTs_files/style.css">
<title>Chapter 1.3: Textures, TPages and CLUTs</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
</head>
<body>
<header>
<h1>Chapter 1.3: Textures, TPages and CLUTs</h1>
</header>
<p>
This tutorial will teach you how to draw graphics with textures, from
converting texture data to loading it onto VRAM, and finally drawing said
texture. This is yet another essential part in PS1 graphics programming,
as not having any textures would not always make for a pretty looking game.
</p>
<p>
This chapter will also cover some development tools to be used for
preparing texture data, such as <b>timtool</b> and <b>img2tim</b>.
</p>
<p>
<b>Compatible with PSn00bSDK:</b> Yes
</p>
<h2>Tutorial Index</h2>
<ul>
<li><a href="#textures">Textures</a></li>
<li><a href="#cluts">Color Look-up Tables (CLUT)</a></li>
<li><a href="#texaddr">Texture Addressing on the PS1</a></li>
<li><a href="#seltexpage">Defining and Selecting a Texture Page</a></li>
<li><a href="#maketexture">Creating a TIM Texture Image</a></li>
<li><a href="#inctexture">Including TIM Image Data</a></li>
<li><a href="#tipsandtricks">Tips, Tricks and Improvements</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
<h2 id="textures">Textures</h2>
<p>
A texture in the context of graphics programming, is basically a bitmap
of pixels that can either be drawn to the screen as a 2D image or
mapped onto polygons to add textures on 3D models.
</p>
<p>
On the PS1 hardware, textures are naturally stored in VRAM alongside the
display and drawing buffers described in previous tutorials. Textures are
generally positioned outside of said visual areas so to not get overwritten
by graphics frames drawn by the GPU. Once texture images have been loaded,
it can then be drawn by textured sprite and/or polygon primitives.
</p>
<p>
The PS1 supports texture color depths of 4, 8 and 16 bits per pixel. 4-bit
and 8-bit textures are usually accompanied with CLUT or Color Lookup Table.
A CLUT is essentially the color palette of its associated texture image.
</p>
<p>
Because the VRAM addresses pixels in 16-bit words, 4-bit and 8-bit textures
are stored at quarter and half of the actual width of the texture respectively
as shown in the image below.
</p>
<center>
<img src="Chapter%201.3%20Textures,%20TPages%20and%20CLUTs_files/vram-texture-widths.png">
<i>4-bit, 8-bit and 16-bit texture images as they appear logically in VRAM</i>
</center>
<p>
This also means that 8-bit textures must have a width that is of a multiple
of 2 whilst 4-bit textures must be of a multiple of 4 to ensure that the pixel
data is word-aligned in VRAM. Failing to do so will often yield artifacts, or
corrupted texture images when trying to upload odd-width images into VRAM.
</p>
<p>
Texture images are usually handled on the PS1 in the TIM file format, which
is a very simple image format designed specifically for the PS1 as it can
hold X and Y coordinates for either image and CLUT data which are used as
target coordinates when uploading the texture to VRAM. TIM files are typically
created from regular image files (bmp, pcx, jpeg or bmp) with tools such as
<b>timtool</b> included in the PsyQ/Programmer Tool SDK,
<a href="https://github.com/lameguy64/img2tim">img2tim</a> which is a free
command-line driven TIM converter and finally,
<a href="https://github.com/lameguy64/timedit">timedit</a> which is essentially
a free albeit slightly dodgy equivalent of <b>timtool</b>.
</p>
<p>
For beginners it may be best to use <b>timedit</b> as its the only free tool
(or at the very least one that I'm aware of) that features a graphical preview
of the TIM image layout in VRAM or stick to <b>timtool</b> if you're using the
PsyQ/Programmers Tool SDK.
</p>
<h2 id="cluts">Color Look-up Tables (CLUT)</h2>
<p>
A CLUT is simply a 16x1 or 256x1 16-bit pixel image that normally accompanies
4-bit and 8-bit texture images respectively. If you haven't guessed by now, a
CLUT is essentially the color palette of the image it accompanies, where each
pixel of the CLUT represents a 16-bit color entry for the texture image
starting from the left (ie. the first pixel from the left represents the color
for index 0 while the very last pixel of the CLUT represents the color for
index 15 or index 255). CLUTs are normally used with 4-bit and 8-bit texture
images, though it can also be used for procedurally generated textures such as
animated plasma effects.
</p>
<p>
The TIM file format could support multiple CLUTs on a single TIM file,
as the CLUT headers in the file format allow for more than 1 pixel high
CLUTs. This is beyond the scope of this part of the tutorial series however.
</p>
<h2 id="texaddr">Texture Addressing on the PS1</h2>
<p>
You may have learned from the last tutorial that the PS1 accesses the VRAM
as a two-dimensional image rather than a more conventional linear framebuffer.
Well, this also applies on how textures in VRAM are 'selected' for drawing with
textured primitives.
</p>
<p>
The PS1 addresses the VRAM in pages, in which the VRAM is divided into a
grid of 16x2 cells of 64x256 16-bit pixels each. The actual texture page
coordinates are still X,Y but with a 64x256 granularity instead. The image
below visually illustrates the cells of each texture page.
</p>
<center>
<img src="Chapter%201.3%20Textures,%20TPages%20and%20CLUTs_files/vram-texture-pages.svg">
<i>Texture page grid of the VRAM</i>
</center>
<p>
Texture pages only applies to the selection of the area at which textures would
be read from by textured graphics primitives, as VRAM coordinates of display
and drawing environments do not adhere to this texture page granularity at all.
Setting a texture page serves as an anchor point at which textured primitives
would source texture data from starting from the top-left corner of the texture
page, with the U,V coordinates of the primitive serving as an offset relative to
the current texture page allowing small portions of a texture page to be read
and drawn, such as animation frames of one particular character in a large
sprite sheet.
</p>
<center>
<img src="Chapter%201.3%20Textures,%20TPages%20and%20CLUTs_files/page-texcoord-relation.svg">
<i>An example of using U,V coordinates to select a particular sprite (in this
case at 48,32) in a sprite sheet</i>
</center>
<p>
Of course this would mean that the texture images would have to be arranged
such that it is placed on the top-right corner of a texture page boundary for
the U,V coordinates to make the most sense. However, some simple offset
translation based on the texture image's position relative to the page boundary
should get around that issue and is going to be covered in this chapter.
</p>
<p>
One thing to consider about texture coordinates that may initially confuse
beginners is that while the width of a 4-bit and 8-bit texture on VRAM varies
from the actual width of the image itself, the texture coordinates does not
need to be adjusted to take that into account as long as the correct color
depth is specified in the texture page value. In this case, if you want to
draw a texture at 96,24 from a 256x256 4-bit texture sheet, you just simply
specify a U,V coordinate of 96,24 in your primitive as if the texture were
still 16-bit.
</p>
<center>
<img src="Chapter%201.3%20Textures,%20TPages%20and%20CLUTs_files/vram-texture-coordinates.svg">
<i>Texture coordinates are always true to the actual size of the
texture image</i>
</center>
<p>
And because the U,V coordinates only have a range of 0-255, it is not possible
to draw a texture image larger than 256x256 pixels regardless of color depth.
To draw larger textures one has to draw multiple primitives to span the entire
size of a larger image, trying to draw a SPRT primitive with a size greater
than 256x256 will only result in a wrap around.
</p>
<h2 id="seltexpage">Defining and Selecting a Texture Page</h2>
<p>
A texture page value is easily defined using the <b>getTPage()</b> macro.
A function version of this macro is present in the PsyQ/Programmers Tool SDK
as <b>GetTPage()</b>, but this is not available in PSn00bSDK as it would be
considered redundant.
</p>
<pre>tpage = getTPage( <i>tp</i>, <i>abr</i>, <i>x</i>, <i>y</i> );
</pre>
<p>
<i>tp</i> specifies the color depth for the texture page in the range of
0 to 2 (0:4-bit, 1:8-bit, 2:16-bit). <i>abr</i> specifies the blend operator
for both non-textured and textured semi-transparent primitives which can be
ignored for now and lastly, <i>x,y</i> specifies the X,Y coordinates of the
VRAM in 16-bit pixel units. Keep in mind that the coordinates will be rounded
down to the next lowest texture page.
</p>
<p>
Now that a texture page value has been defined, there are a number of ways to
set it to the GPU. One is through the <i>tpage</i> field of the <b>DRAWENV</b>
struct which specifies the initial texture page value whenever the drawing
environment is applied. Another is to use a <b>DR_TPAGE</b> primitive which
can be defined with the <b>setDrawTPage()</b> macro which follows the same
syntax as <b>getTPage()</b>. <b>DR_TPAGE</b> is needed for <b>SPRT</b>
primitives which lack a tpage field, though it is also useful for non-textured
primitives to set the blend operator for semi-transparent primitives.
</p>
<p>
Because the PS1 usually processes primitives that have been sorted last first,
<b>DR_TPAGE</b> primitives must be sorted after <b>SPRT</b> or other similar
primitives have been sorted.
</p>
<p>
The following table describes the bit fields of a texture page value which may
come in handy for the more crafty programmers.
</p>
<center>
<table class="bordered-table">
<tbody><tr>
<th>Bits</th>
<td>15-14</td>
<td>13</td>
<td>12</td>
<td>11</td>
<td>10</td>
<td>9</td>
<td>8-7</td>
<td>6-5</td>
<td>4</td>
<td>3-0</td>
</tr>
<tr>
<th>Description</th>
<td>Reserved</td>
<td>Y-flip*</td>
<td>X-flip*</td>
<td>Texture disable*</td>
<td>Draw on displayed area</td>
<td>Dither enable</td>
<td>Texture color depth</td>
<td>Blend operator</td>
<td>Texture page Y (n*256)</td>
<td>Texutre page X (n*64)</td>
</tr>
<tr>
<th colspan="11">*Does not work on <i>really</i> early units, not recommended
to use to maintain compatibility</th>
</tr>
</tbody></table>
</center>
<p>
Whilst on the topic of texture page selection, when working with 4-bit and
8-bit texture images you will also need to use <b>getClut()</b> to define a
CLUT value and is required for 4-bit and 8-bit texture images to draw properly.
Obviously this is not required for 16-bit texture images.
</p>
<pre>clut = getClut( <i>x</i>, <i>y</i> );
</pre>
<p>
<i>x,y</i> specifies the X,Y coordinate of the CLUT within the VRAM.
However, keep in mind that the X axis must be a multiple to 16 pixels for a
CLUT to be defined correctly as otherwise it will be rounded down to the
lowest CLUT value.
</p>
<p>
As for selecting the CLUT, all textured primitives usually have a <i>clut</i>
field in the struct in which the CLUT value can be set to. There is also a
<b>setClut()</b> macro for setting CLUT coordinates to a primitive directly.
</p>
<p>
Usually, the coordinates for texture page and CLUT values are typically derived
from the X,Y coordinates of the TIM image file to take into account TIM images
that are not placed on the top-left corner of the texture page boundary.
</p>
<p>
The following describes the bit fields of a CLUT value.
</p>
<center>
<table class="bordered-table">
<tbody><tr>
<th>Bits</th>
<td>15</td>
<td>14-6</td>
<td>5-0</td>
</tr>
<tr>
<th>Description</th>
<td>Reserved</td>
<td>Y coordinate</td>
<td>X coordinate (n*16)</td>
</tr>
</tbody></table>
</center>
<h2 id="maketexture">Creating a TIM Texture Image</h2>
<p>
There are numerous ways to convert image files into the TIM format, the most
common is by using <b>timtool</b> from the official PsyQ/Programmers Tool SDKs,
or at least those who chose to use that SDK. Another is to use my free but old
command-line converter called <b>img2tim</b>, which follows the same command
line syntax as <b>bmp2tim</b> but supports many more image formats supported
by the FreeImage library and has better conversion options related to
transparencies.
</p>
<p>
Perhaps the most preferable tool to use for those who've stuck to using
PSn00bSDK is <b>timedit</b>, as not only is it free but also features a
similar graphical interface to <b>timtool</b>, on top of extra features
useful for managing a large amount of TIM images, such as grouping.
</p>
<p>
Whichever tool you use, convert the image below into a 8-bit TIM file with
image coordinates of 640,0 and CLUT coordinates of 0,480. You will have to
convert it into a 4-bit or 8-bit TIM as this tutorial is also going to cover
how to work with CLUTs.
</p>
<center>
<img src="Chapter%201.3%20Textures,%20TPages%20and%20CLUTs_files/texture64.png">
</center>
<p>
When converting the image, always remember that texture image and CLUT
coordinates in the tools are always absolute coordinates to the VRAM
regardless of color depth. And in case you're wondering, the PS1 cannot
use 24-bit TIM images, as the GPU can only draw graphics in 16-bit color
depth but can display 24-bit images by entering 24-bit color mode, but
this is beyond the scope of this chapter.
</p>
<h2 id="inctexture">Including TIM Image Data</h2>
<p>
In the meantime, the easiest way to include a binary file into your program
is to include it as an object file by means of a very simple assembler file,
and access that file as an array by defining its symbol name with <h>extern</h>.
Its not ideal for larger projects, but this will do the job for testing purposes.
</p>
<h3>PsyQ/Programmers Tool SDK</h3>
<p>
Save the following as <h>my_image.asm</h>.
</p>
<pre> opt m+,l.,c+
section data ; Store the array in the data section
global tim_my_image ; Define label as global
tim_my_image:
incbin 'my_image.tim' ; Include file data (your TIM)
</pre>
<p>
The name of the data is defined by the label, in this case <h>tim_my_image</h>.
Make sure the label is also defined by a global directive so the linker can find
it when linked against your C program. When writing the assembler file, make sure
line indentations are created with real TAB characters as ASMPSX will throw an
error otherwise.
</p>
<p>
Assemble the file using <h>ASMPSX</h> to turn it into an object file.
</p>
<pre>asmpsx /l my_image.asm,my_image.obj
</pre>
<p>Then link it with your program by simply specifying the object file.</p>
<pre>ccpsx -O2 -Xm -Xo$80010000 my_image.obj program.c -o program.cpe
</pre>
<h3>PSn00bSDK</h3>
<p>
In PSn00bSDK, it works in much the same principle as in the PsyQ SDK,
but this one will be written in GNU assembler syntax. Save the assembler
file with a <h>.s</h> file extension.
</p>
<pre>.section .data
.global tim_my_image
.type tim_my_image, @object
tim_my_image:
.incbin "my_image.tim"
</pre>
<p>
It is recommended to use the makefile from one of the example programs included
with PSn00bSDK, as it has parameters for building with assembler files already
defined and should automatically pick your assembler file as long as it has
a <h>.s</h> file extension.
</p>
<h3>Accessing the Array</h3>
<p>
On both SDKs, the binary file can be accessed as an array by simply defining
it with an <h>extern</h>. Make sure the name matches with the label name defined
in the assembler file.
</p>
<pre>extern int tim_my_image[];
</pre>
<p>
If you get mismatching type errors when compiling, you can simply cast it with a
different pointer type with <h>(u_long*)</h> or <h>(u_int*)</h> depending on
the compiler warnings you're getting. <h>u_int</h> is typically used in PSn00bSDK
instead of <h>u_long</h> as modern GCC interprets <h>u_long</h> as a 64-bit integer
whereas it is a 32-bit integer in PsyQ.
</p>
<h2>Parsing and Uploading the TIM to VRAM</h2>
<p>
To parse a TIM image file, use <b>OpenTIM()</b> to set the TIM file data for
parsing and <b>ReadTIM()</b> to retrieve header information of the TIM file to
a <b>TIM_IMAGE</b> struct. The <b>TIM_IMAGE</b> would contain not only a pointer
to the X,Y and size coordinates of either texture image and CLUT but also
pointers to the image and CLUT data within the TIM file.
</p>
<p>
In PSn00bSDK, <b>GetTimInfo()</b> function instead. It still returns the same
<b>TIM_IMAGE</b> struct.
</p>
<p>
The TIM image coordinates are in the <i>*prect</i> field and CLUT in
the <i>*crect</i> field, both are of type RECT. The actual texture image data
is at <i>*paddr</i> and the CLUT data at <i>*caddr</i>. The color depth of
the TIM file are in bits 0-3 of the <i>mode</i> field and CLUT presence is
determined by testing bit 4.
</p>
<p>
Uploading either pixel or CLUT data is done using <b>LoadImage()</b>, followed
by a call to <b>DrawSync()</b> to wait for texture upload to complete. Whilst
you might be able to get away with not waiting for the texture upload to
finish processing, it is recommended to wait for upload completion as
unpredictable results may occur otherwise.
</p>
<p>
The TIM image upload function should go like this.
</p>
<pre>void LoadTexture(u_long *tim, TIM_IMAGE *tparam) {
// Read TIM information (PsyQ)
OpenTIM(tim);
ReadTIM(tparam);
// Read TIM information (PSn00bSDK)
//GetTimInfo(tim, tparam);
// Upload pixel data to framebuffer
LoadImage(tparam-&gt;prect, (u_long*)tparam-&gt;paddr);
DrawSync(0);
// Upload CLUT to framebuffer if present
if( tparam-&gt;mode &amp; 0x8 ) {
LoadImage(tparam-&gt;crect, (u_long*)tparam-&gt;caddr);
DrawSync(0);
}
}
</pre>
<p>
In PSn00bSDK, you may additionally replace u_long to u_int. They are actually
the same in PsyQ/Programmers Tool whereas in modern GCC/PSn00bSDK u_long
usually defines a 64-bit unsigned integer.
</p>
<p>
Now that you have a TIM upload function, the TIM loading sequence should go like so.
</p>
<pre>extern int tim_my_image[];
// To keep a copy of the TIM coordinates for later
int tim_mode;
RECT tim_prect,tim_crect;
..
void LoadStuff(void) {
// This can be defined locally, if you don't need the TIM coordinates
TIM_IMAGE my_image;
// Load the TIM
LoadTexture((u_long*)tim_my_image, &amp;my_image);
// Copy the TIM coordinates
tim_prect = *my_image.prect;
tim_crect = *my_image.crect;
tim_mode = my_image.mode;
}
</pre>
<p>
Reason you may want to keep a copy of the TIM coordinates separate from the
<b>TIM_IMAGE</b> variable is that once you've figured out how to load files
from CD and load the TIM file to a dynamically allocated buffer, relying on
the <b>TIM_IMAGE</b> struct may not be a good idea as the <i>*prect</i> and
<i>*crect</i> fields point to the TIM file data directly, and will most
likely become undefined data once you've finished uploading that TIM to
VRAM and deallocated its buffer in later parts of your program.
</p>
<h2>Drawing the TIM</h2>
<p>
Now that a texture image has been loaded. The next thing to do is to set
it's texture page to the drawing environment. Since there's only one texture
to deal with, the texture page can be set to the <b>DRAWENV</b> struct.
</p>
<pre>draw[0].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
draw[1].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
</pre>
<p>
To deal with TIMs that are not page aligned, the U,V offset relative to
the TIM's rounded down texture page can be determined with the following
and should work for texture images of any color depth.
</p>
<pre>int tim_uoffs,tim_voffs;
tim_uoffs = (tim_prect.x%64)&lt;&lt;(2-(tim_mode&amp;0x3));
tim_voffs = (tim_prect.y&amp;0xff);
</pre>
<p>
Whilst this would allow texture images to not require being aligned to the
top-left corner of the texture page boundary, texture images cannot cross
between the vertical texture page bounds and for 4-bit texture images,
should not cross the horizontal texture page bounds as otherwise trying to
draw the texture image with a <b>SPRT</b> will result in wrapping in
relation to the texture page.
</p>
<p>
Now to actually draw the texture image. This can be done with a <b>SPRT</b>
primitive which simply draws a textured sprite of a specified size. It doesn't
do fancy things such as rotation and scaling but its a useful primitive for
drawing simple sprites.
</p>
<pre>SPRT *sprt;
...
sprt = (SPRT*)nextpri;
setSprt(sprt); // Initialize the primitive (important)
setXY0(sprt, 48, 48); // Position the sprite at (48,48)
setWH(sprt, 64, 64); // Set sprite size to 64x64 pixels
setUV0(sprt, // Set UV coordinates from TIM offsets
tim_uoffs,
tim_voffs);
setClut(sprt, // Set CLUT coordinates from TIM to sprite
tim_crect.x,
tim_crect.y);
setRGB0(sprt, // Set color of sprite, 128 is neutral
128, 128, 128);
addPrim(ot[db], sprt); // Sort primitive to OT
nextpri += sizeof(SPRT); // Advance next primitive
</pre>
<p>
When dealing with multiple texture images that tend to reside on different
texture pages, you will have to sort a <b>DR_TPAGE</b> primitive right after
the <b>SPRT</b> primitive that requires a particular texture page value set,
as the PS1 processes primitives that are sorted last first.
</p>
<p>
Whilst not required in this chapter, this is how you sort a <b>DR_TPAGE</b>
for when you start playing around with more texture images.
</p>
<pre>DR_TPAGE *tpage;
...
tpage = (DR_TPAGE*)nextpri;
setDrawTPage(tpage, 0, 1, // Set TPage primitive
getTPage(my_image.mode&amp;0x3, 0,
my_image.prect-&gt;x, my_image.prect-&gt;y));
addPrim(ot[db], tpage); // Sort primitive to OT
nextpri += sizeof(DR_TPAGE); // Advance next primitive address
</pre>
<p>
A very simple optimization practice you may want to consider when you start
getting into larger projects is that you only need to sort one <b>DR_TPAGE</b>
primitive if all the sprites sorted prior share a common texture page.
</p>
<h2>Sample Code</h2>
<p>
Working from code in the last tutorial, here's what the code should
look like:
</p>
<pre>#include &lt;sys/types.h&gt; // This provides typedefs needed by libgte.h and libgpu.h
#include &lt;stdio.h&gt; // Not necessary but include it anyway
#include &lt;libetc.h&gt; // Includes some functions that controls the display
#include &lt;libgte.h&gt; // GTE header, not really used but libgpu.h depends on it
#include &lt;libgpu.h&gt; // GPU library header
#define OTLEN 8 // Ordering table length (recommended to set as a define
// so it can be changed easily)
DISPENV disp[2]; // Display/drawing buffer parameters
DRAWENV draw[2];
int db = 0;
// PSn00bSDK requires having all u_long types replaced with
// u_int, as u_long in modern GCC that PSn00bSDK uses defines it as a 64-bit integer.
u_long ot[2][OTLEN]; // Ordering table length
char pribuff[2][32768]; // Primitive buffer
char *nextpri; // Next primitive pointer
int tim_mode; // TIM image parameters
RECT tim_prect,tim_crect;
int tim_uoffs,tim_voffs;
void display() {
DrawSync(0); // Wait for any graphics processing to finish
VSync(0); // Wait for vertical retrace
PutDispEnv(&amp;disp[db]); // Apply the DISPENV/DRAWENVs
PutDrawEnv(&amp;draw[db]);
SetDispMask(1); // Enable the display
DrawOTag(ot[db]+OTLEN-1); // Draw the ordering table
db = !db; // Swap buffers on every pass (alternates between 1 and 0)
nextpri = pribuff[db]; // Reset next primitive pointer
}
// Texture upload function
void LoadTexture(u_long *tim, TIM_IMAGE *tparam) {
// Read TIM parameters (PsyQ)
OpenTIM(tim);
ReadTIM(tparam);
// Read TIM parameters (PSn00bSDK)
//GetTimInfo(tim, tparam);
// Upload pixel data to framebuffer
LoadImage(tparam-&gt;prect, (u_long*)tparam-&gt;paddr);
DrawSync(0);
// Upload CLUT to framebuffer if present
if( tparam-&gt;mode &amp; 0x8 ) {
LoadImage(tparam-&gt;crect, (u_long*)tparam-&gt;caddr);
DrawSync(0);
}
}
void loadstuff(void) {
TIM_IMAGE my_image; // TIM image parameters
extern u_long tim_my_image[];
// Load the texture
LoadTexture(tim_my_image, &amp;my_image);
// Copy the TIM coordinates
tim_prect = *my_image.prect;
tim_crect = *my_image.crect;
tim_mode = my_image.mode;
// Calculate U,V offset for TIMs that are not page aligned
tim_uoffs = (tim_prect.x%64)&lt;&lt;(2-(tim_mode&amp;0x3));
tim_voffs = (tim_prect.y&amp;0xff);
}
// To make main look tidy, init stuff has to be moved here
void init(void) {
// Reset graphics
ResetGraph(0);
// First buffer
SetDefDispEnv(&amp;disp[0], 0, 0, 320, 240);
SetDefDrawEnv(&amp;draw[0], 0, 240, 320, 240);
// Second buffer
SetDefDispEnv(&amp;disp[1], 0, 240, 320, 240);
SetDefDrawEnv(&amp;draw[1], 0, 0, 320, 240);
draw[0].isbg = 1; // Enable clear
setRGB0(&amp;draw[0], 63, 0, 127); // Set clear color (dark purple)
draw[1].isbg = 1;
setRGB0(&amp;draw[1], 63, 0, 127);
nextpri = pribuff[0]; // Set initial primitive pointer address
// load textures and possibly other stuff
loadstuff();
// set tpage of lone texture as initial tpage
draw[0].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
draw[1].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
// apply initial drawing environment
PutDrawEnv(&amp;draw[!db]);
}
int main() {
TILE *tile; // Pointer for TILE
SPRT *sprt; // Pointer for SPRT
// Init stuff
init();
while(1) {
ClearOTagR(ot[db], OTLEN); // Clear ordering table
// Sort textured sprite
sprt = (SPRT*)nextpri;
setSprt(sprt); // Initialize the primitive (very important)
setXY0(sprt, 48, 48); // Position the sprite at (48,48)
setWH(sprt, 64, 64); // Set size to 64x64 pixels
setUV0(sprt, // Set UV coordinates
tim_uoffs,
tim_voffs);
setClut(sprt, // Set CLUT coordinates to sprite
tim_crect.x,
tim_crect.y);
setRGB0(sprt, // Set primitive color
128, 128, 128);
addPrim(ot[db], sprt); // Sort primitive to OT
nextpri += sizeof(SPRT); // Advance next primitive address
// Sort untextured tile primitive from the last tutorial
tile = (TILE*)nextpri; // Cast next primitive
setTile(tile); // Initialize the primitive (very important)
setXY0(tile, 32, 32); // Set primitive (x,y) position
setWH(tile, 64, 64); // Set primitive size
setRGB0(tile, 255, 255, 0); // Set color yellow
addPrim(ot[db], tile); // Add primitive to the ordering table
nextpri += sizeof(TILE); // Advance the next primitive pointer
// Update the display
display();
}
return 0;
}
</pre>
<p>
Compile the example, run it and you should get a yellow square cascaded by
a sprite with your texture image.
</p>
<center>
<img src="Chapter%201.3%20Textures,%20TPages%20and%20CLUTs_files/3-textures.png">
</center>
<p>
You may notice that the untextured rectangle is drawn before the textured
sprite even though the textured sprite was sorted first and the untextured
rectangle last. That's because of the way how primitives are appended to
the ordering table in <b>addPrim()</b>, where the primitive being sorted
is linked right after a primitive that has been sorted to it previously,
and the PS1 hardware parses the ordering table from the top of the array
to the bottom with a reverse ordering table (created with <b>ClearOTagR()</b>).
</p>
<center>
<img src="Chapter%201.3%20Textures,%20TPages%20and%20CLUTs_files/ordertable-multiprims.svg">
<i>How primitives are <b>appended</b> to a preoccupied ordering table entry</i>
</center>
<p>
Primitive 1 would be the <b>SPRT</b> primitive, Primitive 2 would be the
<b>DR_TPAGE</b> primitive (if there was) and lastly, Primitive 3 would be
the untextured <b>TILE</b> primitive. You may think that a reverse
order ordering table makes no sense at first, but this technique is
integral to the PS1's ability to do on-the-fly sorting of polygons when
rendering 3D graphics.
</p>
<h2 id="tipsandtricks">Tips, Tricks and Improvements</h2>
<h3>Pre-calculate tpage, CLUT and UV offset in a struct</h3>
<p>
Using <b>getTPage()</b>, <b>getClut()</b> and <b>setClut()</b> macros on
every sprite sorted isn't exactly the most efficient way of doing things
especially when drawing lots of sprites, not to mention makes your code
look cluttered when managing several TIM images at once. This can be
addressed by defining a struct that contains all the parameters you
need precomputed for drawing a sprite.
</p>
<pre>typedef struct _SPRITE {
u_short tpage; // Tpage value
u_short clut; // CLUT value
u_char u,v; // UV offset (useful for non page aligned TIMs)
u_char w,h; // Size (primitives can only draw 256x256 anyway)
CVECTOR col;
} SPRITE;
...
// Sets parameters to a MYSPRITE using coordinates from TIM_INFO
void GetSprite(TIM_IMAGE *tim, SPRITE *sprite) {
// Get tpage value
sprite-&gt;tpage = getTPage(tim-&gt;mode&amp;0x3, 0,
tim-&gt;prect-&gt;x, tim-&gt;prect-&gt;y);
// Get CLUT value
if( tim-&gt;mode &amp; 0x8 ) {
sprite-&gt;clut = getClut(tim-&gt;crect-&gt;x, tim-&gt;crect-&gt;y);
}
// Set sprite size
sprite-&gt;w = tim-&gt;prect-&gt;w&lt;&lt;(2-tim-&gt;mode&amp;0x3);
sprite-&gt;h = tim-&gt;prect-&gt;h;
// Set UV offset
sprite-&gt;u = (tim-&gt;prect-&gt;x&amp;0x3f)&lt;&lt;(2-tim-&gt;mode&amp;0x3);
sprite-&gt;v = tim-&gt;prect-&gt;y&amp;0xff;
// Set neutral color
sprite-&gt;col.r = 128;
sprite-&gt;col.g = 128;
sprite-&gt;col.b = 128;
}
</pre>
<p>And to draw the sprite, you can write a simple function for it:</p>
<pre>char *SortSprite(int x, int y, u_long *ot, char *pri, SPRITE *sprite) {
SPRT *sprt;
DR_TPAGE *tpage;
sprt = (SPRT*)pri; // initialize the sprite
setSprt(sprt);
setXY0(sprt, x, y); // Set position
setWH(sprt, sprite-&gt;w, sprite-&gt;h); // Set size
setUV0(sprt, sprite-&gt;u, sprite-&gt;v); // Set UV coordinate of sprite
setRGB0(sprt, // Set the color
sprite-&gt;col.r,
sprite-&gt;col.g,
sprite-&gt;col.b);
sprt-&gt;clut = sprite-&gt;clut; // Set the CLUT value
addPrim(ot, sprt); // Sort the primitive and advance
pri += sizeof(SPRT);
tpage = (DR_TPAGE*)pri; // Sort the texture page value
setDrawTPage(tpage, 0, 1, sprite-&gt;tpage);
addPrim(ot, tpage);
return pri+sizeof(DR_TPAGE); // Return new primitive pointer
// (set to nextpri)
}
</pre>
<p>
This method will also work for sprite sheets by simply modifying the
GetSprite() function mentioned earlier such that you can specify an U,V
offset relative to the TIM's U,V offset and the size of the sprite.
</p>
<h3>Use Sprite Sheets</h3>
<p>
Instead of creating a single TIM image for each and every animation frame
of your character sprite, it is best to compile such small images as one
large image. This is called a sprite sheet and allows all sprite frames
to share a common palette if you use 4-bit or 8-bit color depth. If all
sprite frames have the same size, arrange the sprites in a grid where
each cell is the same size as the sprites. This way you can compute the
U,V coordinate of the sprites in the grid easily.
</p>
<h3>Lower color depth textures are faster</h3>
<p>
A 4-bit texture is faster to draw than a 8-bit texture, and a 8-bit
texture is faster to draw than a 16-bit texture, as the GPU has to read
less data from VRAM when drawing textures of lower color depth. Find a
balance that achieves best possible performance without degrading the
quality of your sprites or texture images too much.
</p>
<h3>SPRT_8 and SPRT_16 are faster than SPRT</h3>
<p>
The fixed size sprite primitives are a bit faster than <b>SPRT</b>
primitives, making them best suited for particle sprites of a fixed size
or when drawing tiles of a 2D map.
</p>
<h3>Minimize tpage primitive changes</h3>
<p>
This technique is most applicable when drawing tile maps. If your tile
sheet fits in a single texture page (less than 256x256), you only have
to sort a single <b>DR_TPAGE</b> primitive for all the tiles. This may
also help the GPU maintain texture cache coherency, as well as minimizing
redundant primitive packets.</p>
<h3>Textures don't need to be powers of two</h3>
<p>
Texutures of any size can be used by the GPU, though it is recommended to
make the width of 8-bit TIMs a multiples of 2 and multiples of 4 for 4-bit
TIMs as mentioned earlier in this chapter.
</p>
<h2 id="conclusion">Conclusion</h2>
<p>
This concludes Chapter 1.3. of Lameguy64's PSX Tutorial series. If you've
sifted though this chapter well enough, you should have figured out how to
handle TIM images, uploading them to VRAM and drawing them.
</p>
<p>A few things you may want to experiment with for further learning:</p>
<ul>
<li>Try loading more TIMs and drawing them as individual sprites. Make sure
the TIM image and CLUT do not overlap one another in the TIM editing tool
you're using.</li>
</ul>
<hr>
<table width="100%">
<tbody><tr>
<td width="40%" align="left"><a href="http://lameguy64.net/tutorials/pstutorials/chapter1/2-graphics.html">Previous</a></td>
<td width="20%" align="center"><a href="http://lameguy64.net/tutorials/pstutorials/index.html">Back to Index</a></td>
<td width="40%" align="right"><a href="http://lameguy64.net/tutorials/pstutorials/chapter1/4-controllers.html">Next</a></td>
</tr>
</tbody></table>
</body></html>

705
Docs/Chapter 1.3 Textures, TPages and CLUTs_files/ordertable-multiprims.svg

@ -0,0 +1,705 @@
<?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="420"
height="220"
viewBox="0 0 111.125 58.208337"
version="1.1"
id="svg8"
sodipodi:docname="ordertable-multiprims.svg"
inkscape:version="0.92.1 r15371">
<defs
id="defs2">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker7807"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path7805" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker7561"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path7559"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6581"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path6579" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker6049"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path6047" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5905"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
inkscape:connector-curvature="0"
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path5903" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9889"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9871"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker9806"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path9804"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker6984"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path6982"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5944"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path5942"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5328"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
inkscape:connector-curvature="0"
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5326" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="marker5883"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5881"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker5705"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mstart">
<path
transform="scale(0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path5703"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4561"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.4,0,0,0.4,4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4570"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4984"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4982"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker13622"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path13620"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4575"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4573"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4587"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4585"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4593"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM"
inkscape:collect="always">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4591"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4599"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="TriangleInM">
<path
transform="scale(-0.4)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path4597"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="TriangleInM"
orient="auto"
refY="0"
refX="0"
id="marker4605"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4603"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="scale(-0.4)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="298.22087"
inkscape:cy="212.17404"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="false"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-nodes="true"
inkscape:snap-others="true"
inkscape:object-nodes="true"
inkscape:snap-midpoints="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:bbox-nodes="false"
inkscape:object-paths="true"
inkscape:snap-global="true"
inkscape:snap-text-baseline="true">
<sodipodi:guide
position="0,0"
orientation="0,512"
id="guide4485"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,0"
orientation="-512,0"
id="guide4487"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,135.46666"
orientation="0,-512"
id="guide4489"
inkscape:locked="false" />
<sodipodi:guide
position="0,135.46666"
orientation="512,0"
id="guide4491"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid5333" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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(0,-238.79163)">
<text
id="text7984"
y="267.10205"
x="85.989586"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="267.10205"
x="85.989586"
id="tspan7982"
sodipodi:role="line">Primitive 2</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="48.947918"
height="5.2916636"
x="6.6145835"
y="240.1145" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="244.08325"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="31.750002"
y="244.08325"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[0]=0xffffffff (end)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="295.67703"
id="text4545"><tspan
sodipodi:role="line"
id="tspan4543"
x="31.750002"
y="295.67703"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Start of table</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4984);paint-order:normal"
d="m 5.5562491,242.76034 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
id="path4553"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<rect
y="246.72908"
x="6.6145835"
height="5.2916694"
width="48.947918"
id="rect5546"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5550"
y="250.69783"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="250.69783"
x="31.750002"
id="tspan5548"
sodipodi:role="line">OT[1]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5576"
width="48.947918"
height="5.2916741"
x="6.6145835"
y="253.34367" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="257.31244"
id="text5580"><tspan
sodipodi:role="line"
id="tspan5578"
x="31.750002"
y="257.31244"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[2]</tspan></text>
<rect
y="259.95831"
x="6.6145835"
height="5.2916636"
width="48.947918"
id="rect5582"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5586"
y="263.92706"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="263.92706"
x="31.750002"
id="tspan5584"
sodipodi:role="line">OT[3]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5588"
width="48.947918"
height="5.2916536"
x="6.6145835"
y="266.57288" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="270.54163"
id="text5592"><tspan
sodipodi:role="line"
id="tspan5590"
x="31.750002"
y="270.54163"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[4]</tspan></text>
<rect
y="273.18747"
x="6.6145835"
height="5.2916741"
width="48.947918"
id="rect5594"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5598"
y="277.15622"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="277.15622"
x="31.750002"
id="tspan5596"
sodipodi:role="line">OT[5]</tspan></text>
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5600"
width="48.947918"
height="5.2916636"
x="6.6145835"
y="279.80203" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="31.750002"
y="283.77078"
id="text5604"><tspan
sodipodi:role="line"
id="tspan5602"
x="31.750002"
y="283.77078"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">OT[6]</tspan></text>
<rect
y="286.41666"
x="6.6145835"
height="5.2916536"
width="48.947918"
id="rect5606"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
id="text5610"
y="290.38541"
x="31.750002"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332"
y="290.38541"
x="31.750002"
id="tspan5608"
sodipodi:role="line">OT[7]</tspan></text>
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path13452"
d="m 56.620832,249.37492 2.381253,1e-5 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 h -3.439586"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker13622);paint-order:normal" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4571"
d="m 5.5562491,255.98951 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4575);paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4587);paint-order:normal"
d="m 5.5562491,269.21868 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
id="path4583"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4589"
d="m 56.620832,275.83325 2.381253,10e-6 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 5.55625 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 h -3.439586"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4593);paint-order:normal" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path4595"
d="m 5.5562491,282.44784 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4599);paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4605);paint-order:normal"
d="m 56.620832,289.06242 2.381253,1e-5 c 0.264581,0 0.529164,0.26458 0.529164,0.52917 v 4.23333 c 0,0.26458 -0.264583,0.52916 -0.529164,0.52916 H 42.333332"
id="path4601"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<rect
y="263.39789"
x="68.791664"
height="5.2916584"
width="35.718754"
id="rect5707"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker6049);paint-order:normal"
d="m 67.733333,272.39371 h -5.55625 c -1.852082,0 -0.529166,-3.17499 -2.645833,-3.17499 h -3.968751"
id="path6033"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker6581);paint-order:normal"
d="m 56.620833,262.60413 h 2.910416 c 2.116668,0 0.529165,-7.9375 2.645831,-7.9375 h 44.97917 c 0.79375,0 1.32292,0.52917 1.32292,1.32292 l 0,2.11666 c 0,0.79375 -0.52917,1.32292 -1.30202,1.32292 h -2.66673"
id="path6571"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect7433"
width="35.718754"
height="5.2916689"
x="68.791664"
y="256.78329" />
<rect
y="270.01245"
x="68.791664"
height="5.2916789"
width="35.718754"
id="rect7435"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker7561);paint-order:normal"
d="m 105.56875,266.04371 2.38126,1e-5 c 0.26458,0 0.52916,0.26458 0.52916,0.52917 v 5.55625 c 0,0.26458 -0.26458,0.52916 -0.52916,0.52916 h -3.43959"
id="path7557"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path7803"
d="m 67.733333,259.42913 h -2.38125 c -0.264583,0 -0.529166,0.26458 -0.529166,0.52917 v 5.55625 c 0,0.26458 0.264583,0.52916 0.529166,0.52916 h 3.439584"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.39687499;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker7807);paint-order:normal" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="85.989586"
y="260.48746"
id="text8261"><tspan
sodipodi:role="line"
id="tspan8259"
x="85.989586"
y="260.48746"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Primitive 1</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;text-anchor:end;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="85.989586"
y="273.71664"
id="text8265"><tspan
sodipodi:role="line"
id="tspan8263"
x="85.989586"
y="273.71664"
style="font-size:2.82222223px;text-align:center;text-anchor:middle;fill:#000000;stroke:none;stroke-width:0.26458332">Primitive 3</tspan></text>
</g>
</svg>

268
Docs/Chapter 1.3 Textures, TPages and CLUTs_files/page-texcoord-relation.svg

@ -0,0 +1,268 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="200"
height="300"
viewBox="0 0 52.916664 79.375004"
version="1.1"
id="svg4520"
inkscape:version="0.92.1 r15371"
sodipodi:docname="page-texcoord-relation.svg">
<defs
id="defs4514">
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker5610"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5608"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5111"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="marker5538"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5536"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5117"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path5099"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.3105469"
inkscape:cx="-1.1942734"
inkscape:cy="81.103977"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-global="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1">
<sodipodi:guide
position="0,0"
orientation="0,500"
id="guide5076"
inkscape:locked="false" />
<sodipodi:guide
position="132.29167,0"
orientation="-400,0"
id="guide5078"
inkscape:locked="false" />
<sodipodi:guide
position="132.29167,105.83333"
orientation="0,-500"
id="guide5080"
inkscape:locked="false" />
<sodipodi:guide
position="0,105.83333"
orientation="400,0"
id="guide5082"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata4517">
<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>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-217.62498)">
<image
y="225.03339"
x="7.4083333"
id="image6519"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAGACAMAAAB1HEyMAAAAM1BMVEUAAAD///9mosy2x4f58smA
y//m5ubMib/MxqX/qu7MzMz/VVXMQ0PMiYkAAADr/63/qqqvpluGAAAAAXRSTlMAQObYZgAAAAFi
S0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkCwwBDwIUU2pJAAAFc0lEQVR4
2u3d63LbNhAGULdJm6S39P2ftmJG2yIwSOFCha737J/IlnYBnMxwJMoz38tLVX/e6mWnjp47q3/l
9afMAAAgMcD24r9v1Wo6eu6s/pXXnzIDAAAA3xrqpr3fn90PAACAtwVQ1gzAaD8AAADeFsDe42f1
AwAA4FqAaPqwU703RFb6typfH49HDz89AwCAxADxwq879WjQM/t7D7E0AwCAxABHG28Nuqr/EeD0
DAAAEgOMbL415Ef3r/4HvJoBAACAwzcOAAAAeL8ARwf8eK8ZoJFN1DdOngVYrwMAAIDXzfHkx6pa
mzsLYKvPtzpaawWgPtO21u7VEwCApADxor9u9dO9oiF+3p4rNxePP91q9PBbTxwiDl+u04L41Fmt
g9fn+hcBAIDkALGR8iJUbqJsLi8icfCtvtyqXvzo4GVPCVCvU14Uo6dcK65j5cx4vnUhL88FAACA
/wC2plGAciPPBtiqPmB9Q6R+vjUDAAAAfQCPag9g5E1QC+Coyovu3k3R8vmeMwAAAOD7ewI9G9le
U9+QmP0wVB7gaO3WjZhHX4wcIXx3eAAAkgOUjfUmPt+rBfCsm6KtNVtrPLopWgOUcwEAALD/xUhr
A+WAR1+MfHhQRxez3sP3fjGyh3B49QQAICHAqz8aKDZTNz064Gh/64+e695Ha+09v7cHAAAAHNfP
t/qlqu13V/SP9J02BwCAxADRVDf3DlntBwAAwP8fIP4YKfrj51mA6O89eLkeAAAAxgGiuRzUe4B4
7a+3iv54PAJQrh39IwBbTz0HAAAAfYtvNxDrDzPb70YvYuXFcOYCGPuIg4wAxJzyLF17AAAgOcBZ
NzS2i1D0xgVpde0ehHjN0hkAAEgMUL55qGv0w9Bo/+rap8wBAADAYfUsPtu/uvYpcwAASA4Q9dut
4sKxPR79UuKs/pfFml0fAAAAAAAAAAAAAICMAL/f6497xc9X9K8CzKwPAEBmAOnzAADkBRC+DgAA
AOHrAAAAEL4OAAAA6fMAAOQDiCbp8wAA5ASQPg8AQF4A6fMAAOQFEL4OAACA0WBlAAAAvA8A4esA
AABovUj6PAAAuQCkzwMAkBNA+DoAAACErwMAAED6PAAAOQHKD0TS5wEAyAcgfB0AAABlo/R5AADy
AUifBwAgL0Crrgxfr3tng5eX5gAAkBjgyvD1vd5RhKU5AAAkB2gNGN1EHba6ijcavg4AAIB1gDp0
fRSgDFzvvQCWa82Grx/N6Q5uBAAgOUAMisD12Q9D5YwegHK9+oPMSOjr0RwAAADMfyAaAYjw9Xg8
Eti6t/He8PWjOUvvpAAASAAgfB0AAADS5wEAyAsQdXXo6nRa7FlzAABIDlAe4kcvXsKtICzPAQAA
wGUA5R5mApi3nnoOAAAAxocMJ7ffazZAve5ZXb8+CwAAAI5L+jwAAHkBhK8DAABA+DoAAACErwMA
AED6PAAA+QCiSfo8AAA5AaTPAwCQF0D6PAAAeQGErwMAAGA0WBkAAADvA0D4OgAAAFovkj4PAEAu
AOnzAADkBBC+DgAAAOHrAAAAkD4PAEBOgPIDkfR5AADyAQhfBwAAQNkofR4AgHwA0ucBAMgL0Kor
w9db/ZcFsAMAkBDgyvD16J/tPWUOAADJAerm1dDV7d+R8PQzAMpgNQAAAMzNaQWwzwCUQeyja9Yh
6r17iDWX5gAAkBygDk+feRMyGt5+FJjcu4/ykCtzAADIDLD6RqQMXN96e8PXj26mnBW+PnRTBACA
hADC1wEAACB9HgCAvABRV4evrwa+Ls8BACA5QHywWAk/n108wtJHvlB5yhwAAABcBlDuYTZ8vZ4D
AACA/poNT683MRqe/mbS5wEAyAHwD75wEYolueMsAAAAAElFTkSuQmCC
"
style="image-rendering:optimizeSpeed"
preserveAspectRatio="none"
height="50.799862"
width="33.866665" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect5086"
width="8.4914379"
height="16.938023"
x="32.875015"
y="241.83257" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow2Mend);paint-order:normal"
d="M 7.4083321,225.03338 32.298196,241.38207"
id="path5088"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="M 7.4083331,292.0191 V 225.03338 H 44.693799"
id="path5084"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="15.797976"
y="284.42862"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="15.797976"
y="284.42862"
style="font-size:4.23333311px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332">Texture Page</tspan><tspan
sodipodi:role="line"
x="15.797976"
y="289.72028"
style="font-size:4.23333311px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332"
id="tspan5903">Boundary</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="32.76712"
y="241.02052"
id="text4497-8"><tspan
sodipodi:role="line"
id="tspan4495-5"
x="32.76712"
y="241.02052"
style="font-size:2.82222223px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332">(48,32)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:1.25;font-family:HandelGotDLig;-inkscape-font-specification:HandelGotDLig;text-align:start;text-anchor:start;opacity:1;fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="37.349228"
y="269.88934"
id="text5522"><tspan
sodipodi:role="line"
id="tspan5520"
x="37.349228"
y="283.18051"
style="stroke-width:0.26458332" /></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker5610);paint-order:normal"
d="M 14.873914,285.75994 H 8.9087441"
id="path5534"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
id="text5866"
y="223.74693"
x="6.9488864"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.82222223px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332"
y="223.74693"
x="6.9488864"
id="tspan5864"
sodipodi:role="line">(0,0)</tspan></text>
</g>
</svg>

49
Docs/Chapter 1.3 Textures, TPages and CLUTs_files/style.css

@ -0,0 +1,49 @@
body {
max-width: 900px;
margin: auto;
padding: 8px;
font-family: sans-serif;
font-size: 14px;
//color: white;
//background: black;
}
h {
background-color: #e0e0e0;
padding: 2px;
}
h2 {
border-bottom: 1px solid;
//padding-left: 8px;
}
img {
display: block;
}
.footer-table {
font-size: 14px;
}
.bordered-table {
border-collapse: collapse;
font-size: 11px;
}
.bordered-table th, .bordered-table td {
border: 1px solid;
padding: 4px;
}
hr {
border: none;
border-bottom: 1px solid black;
}
pre {
padding: 8px;
font-size: 12px;
color: black;
background-color: LightGray;
}

313
Docs/Chapter 1.3 Textures, TPages and CLUTs_files/vram-texture-coordinates.svg

@ -0,0 +1,313 @@
<?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="520"
height="290"
viewBox="0 0 137.58333 76.729169"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="vram-texture-coordinates.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.2022732"
inkscape:cx="202.46739"
inkscape:cy="213.9527"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:showpageshadow="false"
inkscape:snap-intersection-paths="true">
<sodipodi:guide
position="0,0"
orientation="0,512"
id="guide4485"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,0"
orientation="-256,0"
id="guide4487"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,67.733332"
orientation="0,-512"
id="guide4489"
inkscape:locked="false" />
<sodipodi:guide
position="0,67.733332"
orientation="256,0"
id="guide4491"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-220.27081)">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="135.46666"
height="67.73333"
x="1.0583369"
y="224.76869"
rx="2.0798286e-006" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="1.3450011"
y="223.73521"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="1.3450011"
y="223.73521"
style="font-size:2.82222223px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332">(0,0)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="136.23978"
y="295.30496"
id="text4497-5"><tspan
sodipodi:role="line"
id="tspan4495-0"
x="136.23978"
y="295.30496"
style="font-size:2.82222223px;text-align:end;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.26458332">(1023,511)</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 69.092673,224.7687 v 67.73333"
id="path4497"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4499"
d="m 10.089578,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 119.66676,224.7687 v 67.73333"
id="path4501"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4503"
d="m 18.518593,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 111.23774,224.7687 v 67.73333"
id="path4505"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4507"
d="m 26.947605,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 102.80873,224.7687 v 67.73333"
id="path4509"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4511"
d="m 35.37662,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 94.379725,224.7687 v 67.73333"
id="path4513"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4515"
d="m 43.805637,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 85.950703,224.7687 v 67.73333"
id="path4517"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4519"
d="m 52.234652,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 77.521688,224.7687 v 67.73333"
id="path4521"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="M 1.0583692,257.12347 H 136.52503"
id="path4525"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4527"
d="m 60.663663,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<rect
style="opacity:1;fill:#ff0000;fill-opacity:0.50196078;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4529"
width="33.716049"
height="32.354763"
x="43.805637"
y="224.76871" />
<text
id="text4533"
y="227.06142"
x="44.105091"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11666656px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.11666656px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332"
y="227.06142"
x="44.105091"
id="tspan4531"
sodipodi:role="line">(0,0)</tspan></text>
<text
id="text4537"
y="256.33563"
x="77.18692"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11666656px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.11666656px;text-align:end;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.26458332"
y="256.33563"
x="77.18692"
id="tspan4535"
sodipodi:role="line">(255,255)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="60.543083"
y="241.99821"
id="text4541"><tspan
sodipodi:role="line"
x="60.543083"
y="241.99821"
style="font-size:2.82222223px;fill:#000000;stroke-width:0.26499999"
id="tspan4545">16-bit</tspan></text>
<rect
y="224.76871"
x="77.521683"
height="32.354763"
width="16.858042"
id="rect4549"
style="opacity:1;fill:#00ff00;fill-opacity:0.50196078;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11666656px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="77.874794"
y="227.06142"
id="text4553"><tspan
sodipodi:role="line"
id="tspan4551"
x="77.874794"
y="227.06142"
style="font-size:2.11666656px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332">(0,0)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11666656px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="94.05928"
y="256.33563"
id="text4557"><tspan
sodipodi:role="line"
id="tspan4555"
x="94.05928"
y="256.33563"
style="font-size:2.11666656px;text-align:end;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.26458332">(255,255)</tspan></text>
<text
id="text4565"
y="241.99821"
x="85.889381"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
id="tspan4563"
style="font-size:2.82222223px;fill:#000000;stroke-width:0.26499999"
y="241.99821"
x="85.889381"
sodipodi:role="line">8-bit</tspan></text>
<rect
style="opacity:1;fill:#0000ff;fill-opacity:0.50196078;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4577"
width="8.4290075"
height="32.354763"
x="94.379723"
y="224.76871" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.82222223px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="98.559776"
y="241.99821"
id="text4581"><tspan
sodipodi:role="line"
x="98.559776"
y="241.99821"
style="font-size:2.82222223px;fill:#000000;stroke-width:0.26499999"
id="tspan4579">4-bit</tspan></text>
<text
id="text7113"
y="227.06142"
x="94.60878"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11666656px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.11666656px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332"
y="227.06142"
x="94.60878"
id="tspan7111"
sodipodi:role="line">(0,0)</tspan></text>
<text
id="text7117"
y="256.33563"
x="102.98763"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11666656px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
xml:space="preserve"><tspan
style="font-size:2.11666656px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332"
y="256.33563"
x="102.98763"
id="tspan7115"
sodipodi:role="line">(255,255)</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4528"
d="m 128.09577,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
</g>
</svg>

192
Docs/Chapter 1.3 Textures, TPages and CLUTs_files/vram-texture-pages.svg

@ -0,0 +1,192 @@
<?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="520"
height="290"
viewBox="0 0 137.58333 76.729169"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="vram-texture-pages.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.2973752"
inkscape:cx="225.21048"
inkscape:cy="187.62673"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-nodes="true"
inkscape:window-width="1440"
inkscape:window-height="848"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:showpageshadow="false">
<sodipodi:guide
position="0,0"
orientation="0,512"
id="guide4485"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,0"
orientation="-256,0"
id="guide4487"
inkscape:locked="false" />
<sodipodi:guide
position="135.46666,67.733332"
orientation="0,-512"
id="guide4489"
inkscape:locked="false" />
<sodipodi:guide
position="0,67.733332"
orientation="256,0"
id="guide4491"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-220.27081)">
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="rect4493"
width="135.46666"
height="67.73333"
x="1.0583369"
y="224.76869"
rx="2.0798286e-006" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="1.3450011"
y="223.73521"
id="text4497"><tspan
sodipodi:role="line"
id="tspan4495"
x="1.3450011"
y="223.73521"
style="font-size:2.82222223px;text-align:start;text-anchor:start;fill:#000000;stroke:none;stroke-width:0.26458332">(0,0)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.41111112px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
x="136.23978"
y="295.30496"
id="text4497-5"><tspan
sodipodi:role="line"
id="tspan4495-0"
x="136.23978"
y="295.30496"
style="font-size:2.82222223px;text-align:end;text-anchor:end;fill:#000000;stroke:none;stroke-width:0.26458332">(1023,511)</tspan></text>
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 68.550851,224.7687 v 67.73333"
id="path4497"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4499"
d="m 9.0721033,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 119.53264,224.7687 v 67.73333"
id="path4501"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4503"
d="m 17.569068,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 111.03567,224.7687 v 67.73333"
id="path4505"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4507"
d="m 26.066032,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 102.53871,224.7687 v 67.73333"
id="path4509"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4511"
d="m 34.562995,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 94.041737,224.7687 v 67.73333"
id="path4513"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4515"
d="m 43.059961,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 85.544775,224.7687 v 67.73333"
id="path4517"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4519"
d="m 51.556923,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="m 77.047814,224.7687 v 67.73333"
id="path4521"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="M 1.0583692,257.12347 H 136.52503"
id="path4525"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4527"
d="m 60.053889,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
<path
inkscape:connector-curvature="0"
id="path4506"
d="m 128.0296,224.7687 v 67.73333"
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.26146019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
</g>
</svg>

672
Docs/Chapter 1.4 Controllers.htm

@ -0,0 +1,672 @@
<html><head><script src="Chapter%201.4%20Controllers_files/analytics.js" type="text/javascript"></script>
<script type="text/javascript">window.addEventListener('DOMContentLoaded',function(){var v=archive_analytics.values;v.service='wb';v.server_name='wwwb-app220.us.archive.org';v.server_ms=361;archive_analytics.send_pageview({});});</script>
<script type="text/javascript" src="Chapter%201.4%20Controllers_files/bundle-playback.js" charset="utf-8"></script>
<script type="text/javascript" src="Chapter%201.4%20Controllers_files/wombat.js" charset="utf-8"></script>
<script type="text/javascript">
__wm.init("http://web.archive.org/web");
__wm.wombat("http://lameguy64.net/tutorials/pstutorials/chapter1/4-controllers.html","20220827033533","http://web.archive.org/","web","/_static/",
"1661571333");
</script>
<link rel="stylesheet" type="text/css" href="Chapter%201.4%20Controllers_files/banner-styles.css">
<link rel="stylesheet" type="text/css" href="Chapter%201.4%20Controllers_files/iconochive.css">
<!-- End Wayback Rewrite JS Include -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="Chapter%201.4%20Controllers_files/style.css">
<title>Chapter 1.4: Controllers</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
</head>
<body><!-- BEGIN WAYBACK TOOLBAR INSERT -->
<style type="text/css">
body {
margin-top:0 !important;
padding-top:0 !important;
/*min-width:800px !important;*/
}
</style>
<script>__wm.rw(0);</script>
<div id="wm-ipp-base" style="display: block; direction: ltr; height: 1px;" lang="en">
</div><div id="wm-ipp-print">The Wayback Machine -
http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter1/4-controllers.html</div>
<script type="text/javascript">//<![CDATA[
__wm.bt(675,27,25,2,"web","http://lameguy64.net/tutorials/pstutorials/chapter1/4-controllers.html","20220827033533",1996,"/_static/",["/_static/css/banner-styles.css?v=fantwOh2","/_static/css/iconochive.css?v=qtvMKcIJ"], false);
__wm.rw(1);
//]]></script>
<!-- END WAYBACK TOOLBAR INSERT -->
<h1>Chapter 1.4: Controllers</h1>
<p>One of the most important aspects when writing software for a game
console is taking input from a controller, as otherwise what's the point of
a game where the player can't take control of it? Unless its some demoscene
stuff you intend to write for the console.</p>
<p>This chapter goes over how to initialize and handle controller input in
your PS1 program. This is something that hasn't really been explained very
well in many tutorials that I've seen in my personal experience, so I'll try
my best to explain how controller input is handled on the PS1 in great
detail.</p>
<p><b>Compatible with PSn00bSDK:</b> Yes</p>
<h2>Tutorial Index</h2>
<ul>
<li><a href="#getinput">Methods to Obtain Controller Input</a></li>
<li><a href="#initpad">Initializing the Pad Subsystem</a></li>
<li><a href="#parsepad">Parsing Controller Data</a></li>
<li><a href="#implementation">Implementation</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
<h2 id="getinput">Methods to Obtain Controller Input</h2>
<p>There are a number of ways to obtain input from the controller on the
PS1; direct hardware access (complicated), through BIOS
<b>InitPAD()/StartPAD()</b> (simpler, but has some limitations), though
<b>PadInit()/PadRead()</b> (even simpler, but only works with digital
pads), and through various controller related libraries such as
libtap, libgun and libpad provided in the PsyQ/Programmers' Tool SDK.</p>
<p>The most common method people tend to use is <b>PadInit()</b> and
<b>PadRead()</b>, and whilst it is the most simplest to use it is not
exactly the most ideal method for a proper game project. For one it only
works with digital pads and Dual-shock pads with analog turned off. Secondly,
there's no way to determine if a pad is disconnected or not and rumble
features on Dual-shock pads cannot be accessed with it. It is, however,
ideal for prototype test programs.</p>
<p>Another method which is a little more ideal is to use <b>InitPAD()</b>
and <b>StartPAD()</b> which are provided by the BIOS ROM of the console. This
method is not only capable of determining if a controller is attached or not
but it also works with a wider variety of controllers including multi-taps.
The only controllers that it doesn't really support properly are both the
Namco and Konami lightguns as they need to be polled in a specific way for
it to work, which is not supported by these functions. Lightguns are beyond
the scope for this chapter anyway. It still cannot access rumble features
of Dual-analog and Dual-shock controllers however.</p>
<p>For compatibility with PSn00bSDK, only the BIOS <b>InitPAD()</b> and
<b>StartPAD()</b> functions will be covered in this chapter. In the future,
I will look into making a follow-up that uses libpad or a similar equivalent
library for PSn00bSDK that would also cover accessing rumble features of
Dual-analog and Dual-shock pads.</p>
<h2 id="initpad">Initializing the Pad Subsystem</h2>
<p>The first step is to define an array of two 34 byte elements. This array
will be used as a buffer for storing incoming controller data which requires
at least about 34 bytes per controller port. It may sound a bit excessive for
storing input data, but this is necessary in case a multitap is connected to
one of the ports, as a multitap will return up to 34 bytes from all four
controllers connected to the tap.</p>
<pre>u_char padbuff[2][34];
</pre>
<p>Next is to call <b>InitPAD()</b> to define the pad array to the BIOS
controller subsystem. libpad still uses the same buffer format that
<b>InitPAD()</b> would return data to, so upgrading from the BIOS pad
routines to libpad should be pretty trivial.</p>
<pre>InitPAD( padbuff[0], 34, padbuff[1], 34 );
</pre>
<p>Before you start controller polling, it may be a good idea to set the
first two elements of both arrays with 0xff, so that your program won't
process faulty input when the array is parsed with zero filled data. You'll
figure out why later in this chapter.</p>
<pre>padbuff[0][0] = padbuff[0][1] = 0xff;
padbuff[1][0] = padbuff[1][1] = 0xff;
</pre>
<p>Then start controller polling with <b>StartPAD()</b>.</p>
<pre>StartPAD();
</pre>
<p>After calling <b>StartPAD()</b> and you have a tty console in your
development setup (or the message window in no$psx), you may see the
message <i>"VSync: Timeout"</i> pop-up when your program reaches a
<b>VSync</b> call. This happens because <b>StartPAD()</b> annoyingly
re-enables automatic VSync interrupt acknowledge in the PS1's kernel,
preventing the <b>VSync()</b> function from detecting a VSync interrupt
from occuring. Fortunately, it has a timeout, of which it will disable
the automatic VSync acknowledge so it can detect VSync interrupts again.
This can happen on both Programmer's Tool and PSn00bSDK.</p>
<p>In PSn00bSDK, you can avoid this message by calling
<b>ChangeClearPAD(1)</b> after <b>StartPAD()</b>, but this function is only
really exposed in PSn00bSDK.</p>
<p>It is generally unnecessary to stop controller polling using
<b>StopPAD()</b>, plus it may cause Dual-shock controllers to reset their
controller mode back to digital mode. If you're using BIOS memory card
functions later down the line, stopping pads will also stop memory cards
as well. Using <b>StopPAD()</b> is only really required when transferring
execution to a child PS-EXE or another PS-EXE altogether.</p>
<h2 id="parsepad">Parsing Controller Data</h2>
<p>After calling <b>StartPAD()</b>, the <h>padbuff</h> array will be filled
with controller data in every frame. For NTSC systems this is 60 times a
second and 50 for PAL systems. Therefore, the controller ports are polled
automatically, so the only thing to do next is to parse the input data
stored in the arrays.</p>
<p>Because the PS1's BIOS controller handler depends on VSync interrupts to
poll the controller ports, you will not be able to receive further inputs
when interrupts are disabled, but this isn't really something to worry about
yet at this point in this tutorial series.</p>
<p>Now, onto the pad buffer data. The first byte stored in the <h>padbuff</h>
array denotes the status of the port. A value of zero indicates that a
device (ie. controller) is connected to the port and the rest of the array
contains valid controller data.</p>
<pre>if( padbuff[0][0] == 0 )
{
// controller on port 1 connected
}
</pre>
<p>The following byte is the controller ID, denoting both the controller
type and the number of bytes the controller has sent to the console. The
controller type is stored in the upper 4 bits of the ID byte while the data
byte is at the lower 4 bits.</p>
<pre>padtype = padbuff[0][1]&gt;&gt;4; // get the controller type
padlen = padbuff[0][1]&amp;0xF; // get the data length (normally not needed)
</pre>
<p>The following table lists controller type values that are relevant to this
chapter. Lightgun IDs are omitted as you won't be able to poll them properly
anyway.</p>
<center>
<table class="bordered-table">
<tbody><tr>
<th>Controller</th><th>Type Value</th>
</tr>
<tr><td>Mouse</td><td>0x1</td></tr>
<tr><td>Namco NegCon</td><td>0x2</td></tr>
<tr><td>Digital pad or Dual-shock in digital mode (no light)</td><td>0x4</td></tr>
<tr><td>Analog Stick or Dual-analog in green mode</td><td>0x5</td></tr>
<tr><td>Dual-shock in analog mode or Dual-analog in red mode</td><td>0x7</td></tr>
<tr><td>Namco JogCon</td><td>0xE</td></tr>
</tbody></table>
</center>
<p>The two bytes following the ID byte are usually the controller's digital
button states as a 16-bit integer, with each bit representing the state
of one button. Oddly, the bit states are inverted, where a bit value of 1
means released and a value of 0 means pressed.</p>
<p>The following table lists which bit of the 16-bit word corresponds to each
button of a standard digital pad or Dual-shock controller. Both controllers
share the same bit positions.</p>
<center>
<table class="bordered-table">
<tbody><tr><th>Bit</th><th>Button</th></tr>
<tr><td>0</td><td>Select</td></tr>
<tr><td>1</td><td>L3 (Dual-shock only)</td></tr>
<tr><td>2</td><td>R3 (Dual-shock only)</td></tr>
<tr><td>3</td><td>Start</td></tr>
<tr><td>4</td><td>Up</td></tr>
<tr><td>5</td><td>Right</td></tr>
<tr><td>6</td><td>Down</td></tr>
<tr><td>7</td><td>Left</td></tr>
<tr><td>8</td><td>L2</td></tr>
<tr><td>9</td><td>R2</td></tr>
<tr><td>10</td><td>L1</td></tr>
<tr><td>11</td><td>R1</td></tr>
<tr><td>12</td><td>Triangle</td></tr>
<tr><td>13</td><td>Circle</td></tr>
<tr><td>14</td><td>Cross</td></tr>
<tr><td>15</td><td>Square</td></tr>
</tbody></table>
</center>
<p>It may be a good idea to define a list of constants for each button so
you can specify which bit to test with more coherent names. In PSn00bSDK,
these are already defined in <h>psxpad.h.</h></p>
<pre>#define PAD_SELECT 1
#define PAD_L3 2
#define PAD_R3 4
#define PAD_START 8
#define PAD_UP 16
#define PAD_RIGHT 32
#define PAD_DOWN 64
#define PAD_LEFT 128
#define PAD_L2 256
#define PAD_R2 512
#define PAD_L1 1024
#define PAD_R1 2048
#define PAD_TRIANGLE 4096
#define PAD_CIRCLE 8192
#define PAD_CROSS 16384
#define PAD_SQUARE 32768
</pre>
<p>To test if a button is pressed, simply mask the 16-bit integer against the
bit value of the button you want to test using an AND (&amp;) operator. Because
the pressed state of a button is zero, you'll have to follow it up with a
NOT (!) operator as well.</p>
<pre>u_short button;
...
button = *((u_short*)(padbuff[0]+2));
// is cross pressed?
if( !( button &amp; PAD_CROSS ) )
{
// do something when cross is pressed
}
</pre>
<p>If you only need to support regular controllers (digital, analog stick,
Dual-analog, Dual-shock), a simplle struct like this should suffice for
all the four controller types and with analog input on controllers with
such features. In PSn00bSDK, the following struct is already defined in
<h>psxpad.h</h>.</p>
<pre>typedef struct _PADTYPE
{
unsigned char stat;
unsigned char len:4;
unsigned char type:4;
unsigned short btn;
unsigned char rs_x,rs_y;
unsigned char ls_x,ls_y;
} PADTYPE;
</pre>
<p>If the connected controller doesn't feature any analog inputs, the
elements following <h>btn</h> relating to analog sticks can be ignored.</p>
<p>When parsing analog stick inputs, remember that the coordinates when the
stick is at its center position is not always 128, due to deadzones and
other factors that affect the potentiometers. Its recommended to implement
a simple threshold to make sure your code does not register false inputs
(at least to the player) when the stick is placed at its center position.</p>
<p>For more information about controller input data, you may want to check
the <a href="http://web.archive.org/web/20220827033533/http://problemkaputt.de/psx-spx.htm#controllersstandarddigitalanalogcontrollers">
Controllers Chapter</a> in nocash's PSX specs document.</p>
<h2 id="implementation">Implementation</h2>
<p>As an exercise for this chapter, we're going to make the textured sprite
from the last chapter move using the controller. Begin by adding the button
definitions, structs and <h>padbuff</h> array described in this chapter near
the beginning of the source file, but must be placed <b>after</b> the
<h>#include</h> directives. When using PSn00bSDK, you can simply include
<h>psxpad.h</h> instead, which already has those defined.</p>
<p>Next, place the <b>InitPAD()</b> and <b>StartPAD()</b> calls at the end
of your <b>init()</b> function, so pads get initialized alongside the
graphics. If you're using PSn00bSDK, you can add <b>ChangeClearPAD(1)</b>
after <b>StartPAD()</b> to avoid the <h>VSync: Timeout</h> message from
cropping up in your tty terminal.</p>
<p>Next, define two variables named <i>pos_x</i> and <i>pos_y</i> of type
<b>int</b> at the start of the <b>main()</b> function, preferably before
the line that defines the <b>TILE</b> variable. These will be for storing
the X,Y coordinates for the textured sprite. Following that, define a
variable <i>pad</i> of type <b>PADTYPE</b>, this will be used for reading
controller inputs more easily.</p>
<p>Before the while loop, set both <i>pos_x</i> and <i>pos_y</i> to 48 to
make sure they don't contain a random undefined value. Within the loop, add
the following code that parses the controller and performs actions according
to controller inputs.</p>
<pre>pad = (PADTYPE*)padbuff[0];
// Only parse inputs when a controller is connected
if( pad-&gt;stat == 0 )
{
// Only parse when a digital pad,
// dual-analog and dual-shock is connected
if( ( pad-&gt;type == 0x4 ) ||
( pad-&gt;type == 0x5 ) ||
( pad-&gt;type == 0x7 ) )
{
if( !(pad-&gt;btn&amp;PAD;_UP) ) // test UP
{
pos_y--;
}
else if( !(pad-&gt;btn&amp;PAD;_UP) ) // test DOWN
{
pos_y++;
}
if( !(pad-&gt;btn&amp;PAD;_LEFT) ) // test LEFT
{
pos_x--;
}
else if( !(pad-&gt;btn&amp;PAD;_RIGHT) ) // test RIGHT
{
pos_x++;
}
}
}
</pre>
<p>Now, go to the bit of code that sorts the textured sprite, and modify
the <b>setXY0</b> macro call to use X,Y coordinates from <i>pos_x</i> and
<i>pos_y</i>.</p>
<pre>setXY0(sprt, pos_x, pos_y);
</pre>
<p>If you followed the instructions properly, the source code should look
like this:</p>
<pre>#include &lt;sys/types.h&gt; // This provides typedefs needed by libgte.h and libgpu.h
#include &lt;stdio.h&gt; // Not necessary but include it anyway
#include &lt;libetc.h&gt; // Includes some functions that controls the display
#include &lt;libgte.h&gt; // GTE header, not really used but libgpu.h depends on it
#include &lt;libgpu.h&gt; // GPU library header
#include &lt;libapi.h&gt; // API header, has InitPAD() and StartPAD() defs
#define OTLEN 8 // Ordering table length (recommended to set as a define
// so it can be changed easily)
DISPENV disp[2]; // Display/drawing buffer parameters
DRAWENV draw[2];
int db = 0;
// PSn00bSDK requires having all u_long types replaced with
// u_int, as u_long in modern GCC that PSn00bSDK uses defines it as a 64-bit integer.
u_long ot[2][OTLEN]; // Ordering table length
char pribuff[2][32768]; // Primitive buffer
char *nextpri; // Next primitive pointer
int tim_mode; // TIM image parameters
RECT tim_prect,tim_crect;
int tim_uoffs,tim_voffs;
// Pad stuff (omit when using PSn00bSDK)
#define PAD_SELECT 1
#define PAD_L3 2
#define PAD_R3 4
#define PAD_START 8
#define PAD_UP 16
#define PAD_RIGHT 32
#define PAD_DOWN 64
#define PAD_LEFT 128
#define PAD_L2 256
#define PAD_R2 512
#define PAD_L1 1024
#define PAD_R1 2048
#define PAD_TRIANGLE 4096
#define PAD_CIRCLE 8192
#define PAD_CROSS 16384
#define PAD_SQUARE 32768
typedef struct _PADTYPE
{
unsigned char stat;
unsigned char len:4;
unsigned char type:4;
unsigned short btn;
unsigned char rs_x,rs_y;
unsigned char ls_x,ls_y;
} PADTYPE;
// pad buffer arrays
u_char padbuff[2][34];
void display() {
DrawSync(0); // Wait for any graphics processing to finish
VSync(0); // Wait for vertical retrace
PutDispEnv(&amp;disp;[db]); // Apply the DISPENV/DRAWENVs
PutDrawEnv(&amp;draw;[db]);
SetDispMask(1); // Enable the display
DrawOTag(ot[db]+OTLEN-1); // Draw the ordering table
db = !db; // Swap buffers on every pass (alternates between 1 and 0)
nextpri = pribuff[db]; // Reset next primitive pointer
}
// Texture upload function
void LoadTexture(u_long *tim, TIM_IMAGE *tparam) {
// Read TIM parameters (PsyQ)
OpenTIM(tim);
ReadTIM(tparam);
// Read TIM parameters (PSn00bSDK)
//GetTimInfo(tim, tparam);
// Upload pixel data to framebuffer
LoadImage(tparam-&gt;prect, (u_long*)tparam-&gt;paddr);
DrawSync(0);
// Upload CLUT to framebuffer if present
if( tparam-&gt;mode &amp; 0x8 ) {
LoadImage(tparam-&gt;crect, (u_long*)tparam-&gt;caddr);
DrawSync(0);
}
}
void loadstuff(void) {
TIM_IMAGE my_image; // TIM image parameters
extern u_long tim_my_image[];
// Load the texture
LoadTexture(tim_my_image, &amp;my;_image);
// Copy the TIM coordinates
tim_prect = *my_image.prect;
tim_crect = *my_image.crect;
tim_mode = my_image.mode;
// Calculate U,V offset for TIMs that are not page aligned
tim_uoffs = (tim_prect.x%64)&lt;&lt;(2-(tim_mode&amp;0x3));
tim_voffs = (tim_prect.y&amp;0xff);
}
// To make main look tidy, init stuff has to be moved here
void init(void) {
// Reset graphics
ResetGraph(0);
// First buffer
SetDefDispEnv(&amp;disp;[0], 0, 0, 320, 240);
SetDefDrawEnv(&amp;draw;[0], 0, 240, 320, 240);
// Second buffer
SetDefDispEnv(&amp;disp;[1], 0, 240, 320, 240);
SetDefDrawEnv(&amp;draw;[1], 0, 0, 320, 240);
draw[0].isbg = 1; // Enable clear
setRGB0(&amp;draw;[0], 63, 0, 127); // Set clear color (dark purple)
draw[1].isbg = 1;
setRGB0(&amp;draw;[1], 63, 0, 127);
nextpri = pribuff[0]; // Set initial primitive pointer address
// load textures and possibly other stuff
loadstuff();
// set tpage of lone texture as initial tpage
draw[0].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
draw[1].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
// apply initial drawing environment
PutDrawEnv(&amp;draw;[!db]);
// Initialize the pads
InitPAD( padbuff[0], 34, padbuff[1], 34 );
// Begin polling
StartPAD();
// To avoid VSync Timeout error, may not be defined in PsyQ
ChangeClearPAD( 1 );
}
int main() {
int pos_x,pos_y;
PADTYPE *pad;
TILE *tile; // Pointer for TILE
SPRT *sprt; // Pointer for SPRT
// Init stuff
init();
pos_x = pos_y = 48;
while(1) {
// Parse controller input
pad = (PADTYPE*)padbuff[0];
// Only parse inputs when a controller is connected
if( pad-&gt;stat == 0 )
{
// Only parse when a digital pad,
// dual-analog and dual-shock is connected
if( ( pad-&gt;type == 0x4 ) ||
( pad-&gt;type == 0x5 ) ||
( pad-&gt;type == 0x7 ) )
{
if( !(pad-&gt;btn&amp;PAD;_UP) ) // test UP
{
pos_y--;
}
else if( !(pad-&gt;btn&amp;PAD;_DOWN) ) // test DOWN
{
pos_y++;
}
if( !(pad-&gt;btn&amp;PAD;_LEFT) ) // test LEFT
{
pos_x--;
}
else if( !(pad-&gt;btn&amp;PAD;_RIGHT) ) // test RIGHT
{
pos_x++;
}
}
}
ClearOTagR(ot[db], OTLEN); // Clear ordering table
// Sort textured sprite
sprt = (SPRT*)nextpri;
setSprt(sprt); // Initialize the primitive (very important)
setXY0(sprt, pos_x, pos_y); // Position the sprite at (48,48)
setWH(sprt, 64, 64); // Set size to 64x64 pixels
setUV0(sprt, // Set UV coordinates
tim_uoffs,
tim_voffs);
setClut(sprt, // Set CLUT coordinates to sprite
tim_crect.x,
tim_crect.y);
setRGB0(sprt, // Set primitive color
128, 128, 128);
addPrim(ot[db], sprt); // Sort primitive to OT
nextpri += sizeof(SPRT); // Advance next primitive address
// Sort untextured tile primitive from the last tutorial
tile = (TILE*)nextpri; // Cast next primitive
setTile(tile); // Initialize the primitive (very important)
setXY0(tile, 32, 32); // Set primitive (x,y) position
setWH(tile, 64, 64); // Set primitive size
setRGB0(tile, 255, 255, 0); // Set color yellow
addPrim(ot[db], tile); // Add primitive to the ordering table
nextpri += sizeof(TILE); // Advance the next primitive pointer
// Update the display
display();
}
return 0;
}
</pre>
<p>Compile, execute and you should get a textured sprite that you can move
around with the directional pad of the controller.</p>
<center>
<img src="Chapter%201.4%20Controllers_files/spritemove.png">
</center>
<h2 id="conclusion">Conclusion</h2>
<p>Hopefully, this chapter should teach you about getting controller input
more than using <b>PadInit()</b> and <b>PadStart()</b>. The only downside
with this method is that you can't control the vibration motors of either
Dual-analog or Dual-shock controllers, or enabling analog mode on Dual-shock
controllers in software. Hopefully, this will be covered in a future chapter
of this tutorial series.</p>
<p>In the next chapter, we'll be looking into handling analog inputs and a
glimpse of fixed-point integer math for performing fractional calculations
without using floats.</p>
<hr>
<table width="100%">
<tbody><tr>
<td width="40%" align="left"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter1/3-textures.html">Previous</a></td>
<td width="20%" align="center"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/index.html">Back to Index</a></td>
<td width="40%" align="right"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter1/5-fixedpoint.html">Next</a></td>
</tr>
</tbody></table>
</body></html>
<!--
FILE ARCHIVED ON 03:35:33 Aug 27, 2022 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 15:39:08 Sep 05, 2022.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->
<!--
playback timings (ms):
captures_list: 132.108
exclusion.robots: 0.302
exclusion.robots.policy: 0.289
RedisCDXSource: 72.486
esindex: 0.008
LoadShardBlock: 40.136 (3)
PetaboxLoader3.datanode: 53.118 (4)
CDXLines.iter: 16.216 (3)
load_resource: 221.534
PetaboxLoader3.resolve: 179.474
-->

474
Docs/Chapter 1.4 Controllers_files/analytics.js

@ -0,0 +1,474 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0
/* eslint-disable no-var, semi, prefer-arrow-callback, prefer-template */
/**
* Collection of methods for sending analytics events to Archive.org's analytics server.
*
* These events are used for internal stats and sent (in anonymized form) to Google Analytics.
*
* @see analytics.md
*
* @type {Object}
*/
window.archive_analytics = (function defineArchiveAnalytics() {
// keep orignal Date object so as not to be affected by wayback's
// hijacking global Date object
var Date = window.Date;
var ARCHIVE_ANALYTICS_VERSION = 2;
var DEFAULT_SERVICE = 'ao_2';
var NO_SAMPLING_SERVICE = 'ao_no_sampling'; // sends every event instead of a percentage
var startTime = new Date();
/**
* @return {Boolean}
*/
function isPerformanceTimingApiSupported() {
return 'performance' in window && 'timing' in window.performance;
}
/**
* Determines how many milliseconds elapsed between the browser starting to parse the DOM and
* the current time.
*
* Uses the Performance API or a fallback value if it's not available.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
*
* @return {Number}
*/
function getLoadTime() {
var start;
if (isPerformanceTimingApiSupported())
start = window.performance.timing.domLoading;
else
start = startTime.getTime();
return new Date().getTime() - start;
}
/**
* Determines how many milliseconds elapsed between the user navigating to the page and
* the current time.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
*
* @return {Number|null} null if the browser doesn't support the Performance API
*/
function getNavToDoneTime() {
if (!isPerformanceTimingApiSupported())
return null;
return new Date().getTime() - window.performance.timing.navigationStart;
}
/**
* Performs an arithmetic calculation on a string with a number and unit, while maintaining
* the unit.
*
* @param {String} original value to modify, with a unit
* @param {Function} doOperation accepts one Number parameter, returns a Number
* @returns {String}
*/
function computeWithUnit(original, doOperation) {
var number = parseFloat(original, 10);
var unit = original.replace(/(\d*\.\d+)|\d+/, '');
return doOperation(number) + unit;
}
/**
* Computes the default font size of the browser.
*
* @returns {String|null} computed font-size with units (typically pixels), null if it cannot be computed
*/
function getDefaultFontSize() {
var fontSizeStr;
if (!('getComputedStyle' in window))
return null;
var style = window.getComputedStyle(document.documentElement);
if (!style)
return null;
fontSizeStr = style.fontSize;
// Don't modify the value if tracking book reader.
if (document.querySelector('#BookReader'))
return fontSizeStr;
return computeWithUnit(fontSizeStr, function reverseBootstrapFontSize(number) {
// Undo the 62.5% size applied in the Bootstrap CSS.
return number * 1.6;
});
}
/**
* Get the URL parameters for a given Location
* @param {Location}
* @return {Object} The URL parameters
*/
function getParams(location) {
if (!location) location = window.location;
var vars;
var i;
var pair;
var params = {};
var query = location.search;
if (!query) return params;
vars = query.substring(1).split('&');
for (i = 0; i < vars.length; i++) {
pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
}
function getMetaProp(name) {
var metaTag = document.querySelector('meta[property=' + name + ']');
return metaTag ? metaTag.getAttribute('content') || null : null;
}
var ArchiveAnalytics = {
/**
* @type {String|null}
*/
service: getMetaProp('service'),
mediaType: getMetaProp('mediatype'),
primaryCollection: getMetaProp('primary_collection'),
/**
* Key-value pairs to send in pageviews (you can read this after a pageview to see what was
* sent).
*
* @type {Object}
*/
values: {},
/**
* Sends an analytics ping, preferably using navigator.sendBeacon()
* @param {Object} values
* @param {Function} [onload_callback] (deprecated) callback to invoke once ping to analytics server is done
* @param {Boolean} [augment_for_ao_site] (deprecated) if true, add some archive.org site-specific values
*/
send_ping: function send_ping(values, onload_callback, augment_for_ao_site) {
if (typeof window.navigator !== 'undefined' && typeof window.navigator.sendBeacon !== 'undefined')
this.send_ping_via_beacon(values);
else
this.send_ping_via_image(values);
},
/**
* Sends a ping via Beacon API
* NOTE: Assumes window.navigator.sendBeacon exists
* @param {Object} values Tracking parameters to pass
*/
send_ping_via_beacon: function send_ping_via_beacon(values) {
var url = this.generate_tracking_url(values || {});
window.navigator.sendBeacon(url);
},
/**
* Sends a ping via Image object
* @param {Object} values Tracking parameters to pass
*/
send_ping_via_image: function send_ping_via_image(values) {
var url = this.generate_tracking_url(values || {});
var loadtime_img = new Image(1, 1);
loadtime_img.src = url;
loadtime_img.alt = '';
},
/**
* Construct complete tracking URL containing payload
* @param {Object} params Tracking parameters to pass
* @return {String} URL to use for tracking call
*/
generate_tracking_url: function generate_tracking_url(params) {
var baseUrl = '//analytics.archive.org/0.gif';
var keys;
var outputParams = params;
var outputParamsArray = [];
outputParams.service = outputParams.service || this.service || DEFAULT_SERVICE;
// Build array of querystring parameters
keys = Object.keys(outputParams);
keys.forEach(function keyIteration(key) {
outputParamsArray.push(encodeURIComponent(key) + '=' + encodeURIComponent(outputParams[key]));
});
outputParamsArray.push('version=' + ARCHIVE_ANALYTICS_VERSION);
outputParamsArray.push('count=' + (keys.length + 2)); // Include `version` and `count` in count
return baseUrl + '?' + outputParamsArray.join('&');
},
/**
* @param {int} page Page number
*/
send_scroll_fetch_event: function send_scroll_fetch_event(page) {
var additionalValues = { ev: page };
var loadTime = getLoadTime();
var navToDoneTime = getNavToDoneTime();
if (loadTime) additionalValues.loadtime = loadTime;
if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
this.send_event('page_action', 'scroll_fetch', location.pathname, additionalValues);
},
send_scroll_fetch_base_event: function send_scroll_fetch_base_event() {
var additionalValues = {};
var loadTime = getLoadTime();
var navToDoneTime = getNavToDoneTime();
if (loadTime) additionalValues.loadtime = loadTime;
if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
this.send_event('page_action', 'scroll_fetch_base', location.pathname, additionalValues);
},
/**
* @param {Object} [options]
* @param {String} [options.mediaType]
* @param {String} [options.mediaLanguage]
* @param {String} [options.page] The path portion of the page URL
*/
send_pageview: function send_pageview(options) {
var settings = options || {};
var defaultFontSize;
var loadTime = getLoadTime();
var mediaType = settings.mediaType;
var primaryCollection = settings.primaryCollection;
var page = settings.page;
var navToDoneTime = getNavToDoneTime();
/**
* @return {String}
*/
function get_locale() {
if (navigator) {
if (navigator.language)
return navigator.language;
else if (navigator.browserLanguage)
return navigator.browserLanguage;
else if (navigator.systemLanguage)
return navigator.systemLanguage;
else if (navigator.userLanguage)
return navigator.userLanguage;
}
return '';
}
defaultFontSize = getDefaultFontSize();
// Set field values
this.values.kind = 'pageview';
this.values.timediff = (new Date().getTimezoneOffset()/60)*(-1); // *timezone* diff from UTC
this.values.locale = get_locale();
this.values.referrer = (document.referrer == '' ? '-' : document.referrer);
if (loadTime)
this.values.loadtime = loadTime;
if (navToDoneTime)
this.values.nav_to_done_ms = navToDoneTime;
if (settings.trackingId) {
this.values.ga_tid = settings.trackingId;
}
/* START CUSTOM DIMENSIONS */
if (defaultFontSize)
this.values.ga_cd1 = defaultFontSize;
if ('devicePixelRatio' in window)
this.values.ga_cd2 = window.devicePixelRatio;
if (mediaType)
this.values.ga_cd3 = mediaType;
if (settings.mediaLanguage) {
this.values.ga_cd4 = settings.mediaLanguage;
}
if (primaryCollection) {
this.values.ga_cd5 = primaryCollection;
}
/* END CUSTOM DIMENSIONS */
if (page)
this.values.page = page;
this.send_ping(this.values);
},
/**
* Sends a tracking "Event".
* @param {string} category
* @param {string} action
* @param {string} label
* @param {Object} additionalEventParams
*/
send_event: function send_event(
category,
action,
label,
additionalEventParams
) {
if (!label) label = window.location.pathname;
if (!additionalEventParams) additionalEventParams = {};
if (additionalEventParams.mediaLanguage) {
additionalEventParams.ga_cd4 = additionalEventParams.mediaLanguage;
delete additionalEventParams.mediaLanguage;
}
var eventParams = Object.assign(
{
kind: 'event',
ec: category,
ea: action,
el: label,
cache_bust: Math.random(),
},
additionalEventParams
);
this.send_ping(eventParams);
},
/**
* Sends every event instead of a small percentage.
*
* Use this sparingly as it can generate a lot of events.
*
* @param {string} category
* @param {string} action
* @param {string} label
* @param {Object} additionalEventParams
*/
send_event_no_sampling: function send_event_no_sampling(
category,
action,
label,
additionalEventParams
) {
var extraParams = additionalEventParams || {};
extraParams.service = NO_SAMPLING_SERVICE;
this.send_event(category, action, label, extraParams);
},
/**
* @param {Object} options see this.send_pageview options
*/
send_pageview_on_load: function send_pageview_on_load(options) {
var self = this;
window.addEventListener('load', function send_pageview_with_options() {
self.send_pageview(options);
});
},
/**
* Handles tracking events passed in URL.
* Assumes category and action values are separated by a "|" character.
* NOTE: Uses the unsampled analytics property. Watch out for future high click links!
* @param {Location}
*/
process_url_events: function process_url_events(location) {
var eventValues;
var actionValue;
var eventValue = getParams(location).iax;
if (!eventValue) return;
eventValues = eventValue.split('|');
actionValue = eventValues.length >= 1 ? eventValues[1] : '';
this.send_event_no_sampling(
eventValues[0],
actionValue,
window.location.pathname
);
},
/**
* Attaches handlers for event tracking.
*
* To enable click tracking for a link, add a `data-event-click-tracking`
* attribute containing the Google Analytics Event Category and Action, separated
* by a vertical pipe (|).
* e.g. `<a href="foobar" data-event-click-tracking="TopNav|FooBar">`
*
* To enable form submit tracking, add a `data-event-form-tracking` attribute
* to the `form` tag.
* e.g. `<form data-event-form-tracking="TopNav|SearchForm" method="GET">`
*
* Additional tracking options can be added via a `data-event-tracking-options`
* parameter. This parameter, if included, should be a JSON string of the parameters.
* Valid parameters are:
* - service {string}: Corresponds to the Google Analytics property data values flow into
*/
set_up_event_tracking: function set_up_event_tracking() {
var self = this;
var clickTrackingAttributeName = 'event-click-tracking';
var formTrackingAttributeName = 'event-form-tracking';
var trackingOptionsAttributeName = 'event-tracking-options';
function handleAction(event, attributeName) {
var selector = '[data-' + attributeName + ']';
var eventTarget = event.target;
if (!eventTarget) return;
var target = eventTarget.closest(selector);
if (!target) return;
var categoryAction;
var categoryActionParts;
var options;
categoryAction = target.dataset[toCamelCase(attributeName)];
if (!categoryAction) return;
categoryActionParts = categoryAction.split('|');
options = target.dataset[toCamelCase(trackingOptionsAttributeName)];
options = options ? JSON.parse(options) : {};
self.send_event(
categoryActionParts[0],
categoryActionParts[1],
categoryActionParts[2] || window.location.pathname,
options.service ? { service: options.service } : {}
);
}
function toCamelCase(str) {
return str.replace(/\W+(.)/g, function (match, chr) {
return chr.toUpperCase();
});
};
document.addEventListener('click', function(e) {
handleAction(e, clickTrackingAttributeName);
});
document.addEventListener('submit', function(e) {
handleAction(e, formTrackingAttributeName);
});
},
/**
* @returns {Object[]}
*/
get_data_packets: function get_data_packets() {
return [this.values];
},
/**
* Creates a tracking image for tracking JS compatibility.
*
* @param {string} type The type value for track_js_case in query params for 0.gif
*/
create_tracking_image: function create_tracking_image(type) {
this.send_ping_via_image({
cache_bust: Math.random(),
kind: 'track_js',
track_js_case: type,
});
}
};
return ArchiveAnalytics;
}());
// @license-end

500
Docs/Chapter 1.4 Controllers_files/banner-styles.css

@ -0,0 +1,500 @@
@import 'record.css'; /* for SPN1 */
#wm-ipp-base {
height:65px;/* initial height just in case js code fails */
padding:0;
margin:0;
border:none;
background:none transparent;
}
#wm-ipp {
z-index: 2147483647;
}
#wm-ipp, #wm-ipp * {
font-family:Lucida Grande, Helvetica, Arial, sans-serif;
font-size:12px;
line-height:1.2;
letter-spacing:0;
width:auto;
height:auto;
max-width:none;
max-height:none;
min-width:0 !important;
min-height:0;
outline:none;
float:none;
text-align:left;
border:none;
color: #000;
text-indent: 0;
position: initial;
background: none;
}
#wm-ipp div, #wm-ipp canvas {
display: block;
}
#wm-ipp div, #wm-ipp tr, #wm-ipp td, #wm-ipp a, #wm-ipp form {
padding:0;
margin:0;
border:none;
border-radius:0;
background-color:transparent;
background-image:none;
/*z-index:2147483640;*/
height:auto;
}
#wm-ipp table {
border:none;
border-collapse:collapse;
margin:0;
padding:0;
width:auto;
font-size:inherit;
}
#wm-ipp form input {
padding:1px !important;
height:auto;
display:inline;
margin:0;
color: #000;
background: none #fff;
border: 1px solid #666;
}
#wm-ipp form input[type=submit] {
padding:0 8px !important;
margin:1px 0 1px 5px !important;
width:auto !important;
border: 1px solid #000 !important;
background: #fff !important;
color: #000 !important;
}
#wm-ipp a {
display: inline;
}
#wm-ipp a:hover{
text-decoration:underline;
}
#wm-ipp a.wm-btn:hover {
text-decoration:none;
color:#ff0 !important;
}
#wm-ipp a.wm-btn:hover span {
color:#ff0 !important;
}
#wm-ipp #wm-ipp-inside {
margin: 0 6px;
border:5px solid #000;
border-top:none;
background-color:rgba(255,255,255,0.9);
-moz-box-shadow:1px 1px 4px #333;
-webkit-box-shadow:1px 1px 4px #333;
box-shadow:1px 1px 4px #333;
border-radius:0 0 8px 8px;
}
/* selectors are intentionally verbose to ensure priority */
#wm-ipp #wm-logo {
padding:0 10px;
vertical-align:middle;
min-width:100px;
flex: 0 0 100px;
}
#wm-ipp .c {
padding-left: 4px;
}
#wm-ipp .c .u {
margin-top: 4px !important;
}
#wm-ipp .n {
padding:0 0 0 5px !important;
vertical-align: bottom;
}
#wm-ipp .n a {
text-decoration:none;
color:#33f;
font-weight:bold;
}
#wm-ipp .n .b {
padding:0 6px 0 0 !important;
text-align:right !important;
overflow:visible;
white-space:nowrap;
color:#99a;
vertical-align:middle;
}
#wm-ipp .n .y .b {
padding:0 6px 2px 0 !important;
}
#wm-ipp .n .c {
background:#000;
color:#ff0;
font-weight:bold;
padding:0 !important;
text-align:center;
}
#wm-ipp.hi .n td.c {
color:#ec008c;
}
#wm-ipp .n td.f {
padding:0 0 0 6px !important;
text-align:left !important;
overflow:visible;
white-space:nowrap;
color:#99a;
vertical-align:middle;
}
#wm-ipp .n tr.m td {
text-transform:uppercase;
white-space:nowrap;
padding:2px 0;
}
#wm-ipp .c .s {
padding:0 5px 0 0 !important;
vertical-align:bottom;
}
#wm-ipp #wm-nav-captures {
white-space: nowrap;
}
#wm-ipp .c .s a.t {
color:#33f;
font-weight:bold;
line-height: 1.8;
}
#wm-ipp .c .s div.r {
color: #666;
font-size:9px;
white-space:nowrap;
}
#wm-ipp .c .k {
padding-bottom:1px;
}
#wm-ipp .c .s {
padding:0 5px 2px 0 !important;
}
#wm-ipp td#displayMonthEl {
padding: 2px 0 !important;
}
#wm-ipp td#displayYearEl {
padding: 0 0 2px 0 !important;
}
div#wm-ipp-sparkline {
position:relative;/* for positioning markers */
white-space:nowrap;
background-color:#fff;
cursor:pointer;
line-height:0.9;
}
#sparklineImgId, #wm-sparkline-canvas {
position:relative;
z-index:9012;
max-width:none;
}
#wm-ipp-sparkline div.yt {
position:absolute;
z-index:9010 !important;
background-color:#ff0 !important;
top: 0;
}
#wm-ipp-sparkline div.mt {
position:absolute;
z-index:9013 !important;
background-color:#ec008c !important;
top: 0;
}
#wm-ipp .r {
margin-left: 4px;
}
#wm-ipp .r a {
color:#33f;
border:none;
position:relative;
background-color:transparent;
background-repeat:no-repeat !important;
background-position:100% 100% !important;
text-decoration: none;
}
#wm-ipp #wm-capinfo {
/* prevents notice div background from sticking into round corners of
#wm-ipp-inside */
border-radius: 0 0 4px 4px;
}
#wm-ipp #wm-capinfo .c-logo {
display:block;
float:left;
margin-right:3px;
width:90px;
min-height:90px;
max-height: 290px;
border-radius:45px;
overflow:hidden;
background-position:50%;
background-size:auto 90px;
box-shadow: 0 0 2px 2px rgba(208,208,208,128) inset;
}
#wm-ipp #wm-capinfo .c-logo span {
display:inline-block;
}
#wm-ipp #wm-capinfo .c-logo img {
height:90px;
position:relative;
left:-50%;
}
#wm-ipp #wm-capinfo .wm-title {
font-size:130%;
}
#wm-ipp #wm-capinfo a.wm-selector {
display:inline-block;
color: #aaa;
text-decoration:none !important;
padding: 2px 8px;
}
#wm-ipp #wm-capinfo a.wm-selector.selected {
background-color:#666;
}
#wm-ipp #wm-capinfo a.wm-selector:hover {
color: #fff;
}
#wm-ipp #wm-capinfo.notice-only #wm-capinfo-collected-by,
#wm-ipp #wm-capinfo.notice-only #wm-capinfo-timestamps {
display: none;
}
#wm-ipp #wm-capinfo #wm-capinfo-notice .wm-capinfo-content {
background-color:#ff0;
padding:5px;
font-size:14px;
text-align:center;
}
#wm-ipp #wm-capinfo #wm-capinfo-notice .wm-capinfo-content * {
font-size:14px;
text-align:center;
}
#wm-ipp #wm-expand {
right: 1px;
bottom: -1px;
color: #ffffff;
background-color: #666 !important;
padding:0 5px 0 3px !important;
border-radius: 3px 3px 0 0 !important;
}
#wm-ipp #wm-expand span {
color: #ffffff;
}
#wm-ipp #wm-expand #wm-expand-icon {
display: inline-block;
transition: transform 0.5s;
transform-origin: 50% 45%;
}
#wm-ipp #wm-expand.wm-open #wm-expand-icon {
transform: rotate(180deg);
}
#wm-ipp #wmtb {
text-align:right;
}
#wm-ipp #wmtb #wmtbURL {
width: calc(100% - 45px);
}
#wm-ipp #wm-graph-anchor {
border-right:1px solid #ccc;
}
/* time coherence */
html.wb-highlight {
box-shadow: inset 0 0 0 3px #a50e3a !important;
}
.wb-highlight {
outline: 3px solid #a50e3a !important;
}
#wm-ipp-print {
display:none !important;
}
@media print {
#wm-ipp-base {
display:none !important;
}
#wm-ipp-print {
display:block !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
@media (max-width:414px) {
#wm-ipp .xxs {
display:none !important;
}
}
@media (min-width:1055px) {
#wm-ipp #wm-graph-anchor {
display:block !important;
}
}
@media (max-width:1054px) {
#wm-ipp #wm-graph-anchor {
display:none !important;
}
}
@media (max-width:1163px) {
#wm-logo {
display:none !important;
}
}
#wm-btns {
white-space: nowrap;
margin-top: -2px;
}
#wm-btns #wm-save-snapshot-open {
margin-right: 7px;
top: -6px;
}
#wm-btns #wm-sign-in {
box-sizing: content-box;
display: none;
margin-right: 7px;
top: -8px;
/*
round border around sign in button
*/
border: 2px #000 solid;
border-radius: 14px;
padding-right: 2px;
padding-bottom: 2px;
width: 11px;
height: 11px;
}
#wm-btns #wm-sign-in>.iconochive-person {
font-size: 12.5px;
}
#wm-save-snapshot-open > .iconochive-web {
color:#000;
font-size:160%;
}
#wm-ipp #wm-share {
display: flex;
align-items: flex-end;
justify-content: space-between;
}
#wm-share > #wm-screenshot {
display: inline-block;
margin-right: 3px;
visibility: hidden;
}
#wm-screenshot > .iconochive-image {
color:#000;
font-size:160%;
}
#wm-share > #wm-video {
display: inline-block;
margin-right: 3px;
visibility: hidden;
}
#wm-video > .iconochive-movies {
color: #000;
display: inline-block;
font-size: 150%;
margin-bottom: 2px;
}
#wm-btns #wm-save-snapshot-in-progress {
display: none;
font-size:160%;
opacity: 0.5;
position: relative;
margin-right: 7px;
top: -5px;
}
#wm-btns #wm-save-snapshot-success {
display: none;
color: green;
position: relative;
top: -7px;
}
#wm-btns #wm-save-snapshot-fail {
display: none;
color: red;
position: relative;
top: -7px;
}
.wm-icon-screen-shot {
background: url("../images/web-screenshot.svg") no-repeat !important;
background-size: contain !important;
width: 22px !important;
height: 19px !important;
display: inline-block;
}
#donato {
/* transition effect is disable so as to simplify height adjustment */
/*transition: height 0.5s;*/
height: 0;
margin: 0;
padding: 0;
border-bottom: 1px solid #999 !important;
}
body.wm-modal {
height: auto !important;
overflow: hidden !important;
}
#donato #donato-base {
width: 100%;
height: 100%;
/*bottom: 0;*/
margin: 0;
padding: 0;
position: absolute;
z-index: 2147483639;
}
body.wm-modal #donato #donato-base {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2147483640;
}
.wb-autocomplete-suggestions {
font-family: Lucida Grande, Helvetica, Arial, sans-serif;
font-size: 12px;
text-align: left;
cursor: default;
border: 1px solid #ccc;
border-top: 0;
background: #fff;
box-shadow: -1px 1px 3px rgba(0,0,0,.1);
position: absolute;
display: none;
z-index: 2147483647;
max-height: 254px;
overflow: hidden;
overflow-y: auto;
box-sizing: border-box;
}
.wb-autocomplete-suggestion {
position: relative;
padding: 0 .6em;
line-height: 23px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.02em;
color: #333;
}
.wb-autocomplete-suggestion b {
font-weight: bold;
}
.wb-autocomplete-suggestion.selected {
background: #f0f0f0;
}

3
Docs/Chapter 1.4 Controllers_files/bundle-playback.js
File diff suppressed because it is too large
View File

116
Docs/Chapter 1.4 Controllers_files/iconochive.css

@ -0,0 +1,116 @@
@font-face{font-family:'Iconochive-Regular';src:url('https://archive.org/includes/fonts/Iconochive-Regular.eot?-ccsheb');src:url('https://archive.org/includes/fonts/Iconochive-Regular.eot?#iefix-ccsheb') format('embedded-opentype'),url('https://archive.org/includes/fonts/Iconochive-Regular.woff?-ccsheb') format('woff'),url('https://archive.org/includes/fonts/Iconochive-Regular.ttf?-ccsheb') format('truetype'),url('https://archive.org/includes/fonts/Iconochive-Regular.svg?-ccsheb#Iconochive-Regular') format('svg');font-weight:normal;font-style:normal}
[class^="iconochive-"],[class*=" iconochive-"]{font-family:'Iconochive-Regular'!important;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
.iconochive-Uplevel:before{content:"\21b5"}
.iconochive-exit:before{content:"\1f6a3"}
.iconochive-beta:before{content:"\3b2"}
.iconochive-logo:before{content:"\1f3db"}
.iconochive-audio:before{content:"\1f568"}
.iconochive-movies:before{content:"\1f39e"}
.iconochive-software:before{content:"\1f4be"}
.iconochive-texts:before{content:"\1f56e"}
.iconochive-etree:before{content:"\1f3a4"}
.iconochive-image:before{content:"\1f5bc"}
.iconochive-web:before{content:"\1f5d4"}
.iconochive-collection:before{content:"\2211"}
.iconochive-folder:before{content:"\1f4c2"}
.iconochive-data:before{content:"\1f5c3"}
.iconochive-tv:before{content:"\1f4fa"}
.iconochive-article:before{content:"\1f5cf"}
.iconochive-question:before{content:"\2370"}
.iconochive-question-dark:before{content:"\3f"}
.iconochive-info:before{content:"\69"}
.iconochive-info-small:before{content:"\24d8"}
.iconochive-comment:before{content:"\1f5e9"}
.iconochive-comments:before{content:"\1f5ea"}
.iconochive-person:before{content:"\1f464"}
.iconochive-people:before{content:"\1f465"}
.iconochive-eye:before{content:"\1f441"}
.iconochive-rss:before{content:"\221e"}
.iconochive-time:before{content:"\1f551"}
.iconochive-quote:before{content:"\275d"}
.iconochive-disc:before{content:"\1f4bf"}
.iconochive-tv-commercial:before{content:"\1f4b0"}
.iconochive-search:before{content:"\1f50d"}
.iconochive-search-star:before{content:"\273d"}
.iconochive-tiles:before{content:"\229e"}
.iconochive-list:before{content:"\21f6"}
.iconochive-list-bulleted:before{content:"\2317"}
.iconochive-latest:before{content:"\2208"}
.iconochive-left:before{content:"\2c2"}
.iconochive-right:before{content:"\2c3"}
.iconochive-left-solid:before{content:"\25c2"}
.iconochive-right-solid:before{content:"\25b8"}
.iconochive-up-solid:before{content:"\25b4"}
.iconochive-down-solid:before{content:"\25be"}
.iconochive-dot:before{content:"\23e4"}
.iconochive-dots:before{content:"\25a6"}
.iconochive-columns:before{content:"\25af"}
.iconochive-sort:before{content:"\21d5"}
.iconochive-atoz:before{content:"\1f524"}
.iconochive-ztoa:before{content:"\1f525"}
.iconochive-upload:before{content:"\1f4e4"}
.iconochive-download:before{content:"\1f4e5"}
.iconochive-favorite:before{content:"\2605"}
.iconochive-heart:before{content:"\2665"}
.iconochive-play:before{content:"\25b6"}
.iconochive-play-framed:before{content:"\1f3ac"}
.iconochive-fullscreen:before{content:"\26f6"}
.iconochive-mute:before{content:"\1f507"}
.iconochive-unmute:before{content:"\1f50a"}
.iconochive-share:before{content:"\1f381"}
.iconochive-edit:before{content:"\270e"}
.iconochive-reedit:before{content:"\2710"}
.iconochive-gear:before{content:"\2699"}
.iconochive-remove-circle:before{content:"\274e"}
.iconochive-plus-circle:before{content:"\1f5d6"}
.iconochive-minus-circle:before{content:"\1f5d5"}
.iconochive-x:before{content:"\1f5d9"}
.iconochive-fork:before{content:"\22d4"}
.iconochive-trash:before{content:"\1f5d1"}
.iconochive-warning:before{content:"\26a0"}
.iconochive-flash:before{content:"\1f5f2"}
.iconochive-world:before{content:"\1f5fa"}
.iconochive-lock:before{content:"\1f512"}
.iconochive-unlock:before{content:"\1f513"}
.iconochive-twitter:before{content:"\1f426"}
.iconochive-facebook:before{content:"\66"}
.iconochive-googleplus:before{content:"\67"}
.iconochive-reddit:before{content:"\1f47d"}
.iconochive-tumblr:before{content:"\54"}
.iconochive-pinterest:before{content:"\1d4df"}
.iconochive-popcorn:before{content:"\1f4a5"}
.iconochive-email:before{content:"\1f4e7"}
.iconochive-embed:before{content:"\1f517"}
.iconochive-gamepad:before{content:"\1f579"}
.iconochive-Zoom_In:before{content:"\2b"}
.iconochive-Zoom_Out:before{content:"\2d"}
.iconochive-RSS:before{content:"\1f4e8"}
.iconochive-Light_Bulb:before{content:"\1f4a1"}
.iconochive-Add:before{content:"\2295"}
.iconochive-Tab_Activity:before{content:"\2318"}
.iconochive-Forward:before{content:"\23e9"}
.iconochive-Backward:before{content:"\23ea"}
.iconochive-No_Audio:before{content:"\1f508"}
.iconochive-Pause:before{content:"\23f8"}
.iconochive-No_Favorite:before{content:"\2606"}
.iconochive-Unike:before{content:"\2661"}
.iconochive-Song:before{content:"\266b"}
.iconochive-No_Flag:before{content:"\2690"}
.iconochive-Flag:before{content:"\2691"}
.iconochive-Done:before{content:"\2713"}
.iconochive-Check:before{content:"\2714"}
.iconochive-Refresh:before{content:"\27f3"}
.iconochive-Headphones:before{content:"\1f3a7"}
.iconochive-Chart:before{content:"\1f4c8"}
.iconochive-Bookmark:before{content:"\1f4d1"}
.iconochive-Documents:before{content:"\1f4da"}
.iconochive-Newspaper:before{content:"\1f4f0"}
.iconochive-Podcast:before{content:"\1f4f6"}
.iconochive-Radio:before{content:"\1f4fb"}
.iconochive-Cassette:before{content:"\1f4fc"}
.iconochive-Shuffle:before{content:"\1f500"}
.iconochive-Loop:before{content:"\1f501"}
.iconochive-Low_Audio:before{content:"\1f509"}
.iconochive-First:before{content:"\1f396"}
.iconochive-Invisible:before{content:"\1f576"}
.iconochive-Computer:before{content:"\1f5b3"}

70
Docs/Chapter 1.4 Controllers_files/style.css

@ -0,0 +1,70 @@
body {
max-width: 900px;
margin: auto;
padding: 8px;
font-family: sans-serif;
font-size: 14px;
//color: white;
//background: black;
}
h {
background-color: #e0e0e0;
padding: 2px;
}
h2 {
border-bottom: 1px solid;
//padding-left: 8px;
}
img {
display: block;
}
.footer-table {
font-size: 14px;
}
.bordered-table {
border-collapse: collapse;
font-size: 11px;
}
.bordered-table th, .bordered-table td {
border: 1px solid;
padding: 4px;
}
hr {
border: none;
border-bottom: 1px solid black;
}
pre {
padding: 8px;
font-size: 12px;
color: black;
background-color: LightGray;
}
/*
FILE ARCHIVED ON 03:35:25 Aug 27, 2022 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 15:39:09 Sep 05, 2022.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
*/
/*
playback timings (ms):
captures_list: 107.165
exclusion.robots: 0.073
exclusion.robots.policy: 0.067
cdx.remote: 0.064
esindex: 0.009
LoadShardBlock: 52.713 (3)
PetaboxLoader3.datanode: 140.466 (4)
CDXLines.iter: 14.771 (3)
load_resource: 139.896
PetaboxLoader3.resolve: 47.824
*/

21
Docs/Chapter 1.4 Controllers_files/wombat.js
File diff suppressed because it is too large
View File

826
Docs/Chapter 1.5 Fixed point Math.htm

@ -0,0 +1,826 @@
<html><head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="Chapter%201.5%20Fixed%20point%20Math_files/style.css">
<title>Chapter 1.5: Fixed point Math</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
</head>
<body>
<h1>Chapter 1.5: Fixed Point Math</h1>
<p>If you've been trying to write some games on a modern system (ie. your
PC), you probably already know about using floats to implement momentum and
jumping physics in a 2D platformer, or have something move towards a direction
specified in degrees rather than X,Y velocity values to have said object
move at an angle, like a ship in an Asteroids style game or a car in a
top-down racer... On the PlayStation, these principles still apply. But
there's a problem; the PlayStation does not have a hardware floating point
unit.</p>
<p>Whilst you can still use floats on the PlayStation as the compiler will
resort to software emulation to perform such operations, which you might
be able to get away with, it's not exactly the most ideal method as software
emulation of floats is quite slow, and will become an issue if used for
collision detection or processing movement of a hundred projectile
entities... The alternative that's better suited for a system without a
floating point unit is to use a integer based fractional number system
commonly known as fixed point math.</p>
<p>As the name suggests, fixed point math is a trick for storing fractional
numbers with fixed points, in this case an integer scale of 4096 will have
a range between zero to 4095 representing a fractional value, with 4096
representing a integer value of 1. Fixed point math is used heavily in games
made for systems that lacked a floating point unit (5th generation and older
consoles), or where integer math is considerably faster than floating point
math and not all systems feature a floating point unit
(ie. IBM compatible PCs).</p>
<p>This chapter covers the general idea and basics of performing fixed point
integer arithmetic. This is a highly essential chapter when getting into
PlayStation homebrew development, as learning it will increase the range of
games you can write for the console immensely. If you've already learned some
binary encoding of numeric values this chapter might be a bit easier to
understand.</p>
<p><b>Compatible with PSn00bSDK:</b> Yes</p>
<h2>Tutorial Index</h2>
<ul>
<li><a href="#principles">Principle of Fixed Point Math</a></li>
<li><a href="#basics">Fixed Point Arithmetic Basics</a></li>
<li><a href="#tankcontrols">Implementing Tank Controls with Fixed Point</a></li>
<li><a href="#asteroids">Asteroids Style Physics with Fixed Point</a></li>
<li><a href="#spriterot">Bonus: Fixed Point Sprite Rotation</a></li>
<li><a href="#limitations">Limitations of Fixed Point Math</a></li>
<li><a href="#conclusion">Conclusion and Further Reading</a></li>
</ul>
<h2 id="principles">Principle of Fixed Point Math</h2>
<p>The basic principle of fixed point integer math is instead of representing
a real number of 1.25 as a floating point number, you instead represent
the number as an integer value from a scale value, in this case 4096 which is
defined as <b>ONE</b> in the GTE library headers. So a real value of 1.25
will look like 5120 when converted to fixed point math with a scale of 4096.
Converting a floating point number to a fixed point number is achieved by
simply multiplying the real number against the scale value and rounding off
the fractions, turning the result into a plain integer value. The following
table shows some sample floating point values represented in fixed point.</p>
<center>
<table class="bordered-table">
<tbody><tr>
<th>Floating point representation</th><th>Fixed point representation</th>
</tr>
<tr><td>1.25</td><td>5120</td></tr>
<tr><td>0.75</td><td>3072</td></tr>
<tr><td>0.2</td><td>819</td></tr>
<tr><td>21.284</td><td>87179</td></tr>
<tr><td colspan="2"><center>1.0 = 4096</center></td></tr>
</tbody></table>
</center>
<p>Using a scale value of 4096 is most ideal for PlayStation projects not
only because it provides a good balance between precision and the maximum
decimal value it can store, alongside allowing fixed point values to be
rounded and divided quickly with simple bit shift operations and AND masks,
but also because the Geometry Transformation Engine (GTE) also uses the
same scale value for some of its registers. Any scale value can be used to
gain more precision or to increase the decimal range limit. Generally
a power of two scale value is recommended for performance reasons.</p>
<center>
<table class="bordered-table">
<tbody><tr>
<td><b>Bits</b></td>
<td>31</td><td>30</td><td>29</td><td>28</td><td>27</td><td>26</td><td>25</td>
<td>24</td><td>23</td><td>22</td><td>21</td><td>20</td><td>19</td><td>18</td>
<td>17</td><td>16</td><td>15</td><td>14</td><td>13</td><td>12</td><td>11</td>
<td>10</td><td>9</td><td>8</td><td>7</td><td>6</td><td>5</td><td>4</td>
<td>3</td><td>2</td><td>1</td><td>0</td>
</tr>
<tr>
<td><b>Description</b></td>
<td>Sign</td>
<td colspan="19">Decimal (19 bits)</td>
<td colspan="12">Fractional (12 bits)</td>
</tr>
</tbody></table>
</center>
<p>The table above illustrates a fixed point value with a scale value
of 4096 in a signed 32-bit integer. As there's only 19 bits available for
the decimal portion the maximum range for the decimal value is -524288 to
524287.</p>
<h2 id="basics">Fixed Point Arithmetic Basics</h2>
<p>Simple mathematical operations in fixed point such as addition and
subtraction is not that much different to performing the same operations
with integers, only values have to be based around the scale value.</p>
<pre>fixed_value += 4096; // += 1.0
fixed_value -= 4096; // -= 1.0
fixed_value += 2048; // += 0.5
fixed_value -= 6144; // -= 1.5
</pre>
<p>For decimal multiplication and divide operations, the value for the
dividend or multiplicand stays as-is.</p>
<pre>fixed_value *= 5; // *= 5;
fixed_value /= 10; // /= 10;
</pre>
<p>The equation for performing fractional multiplications is a little
tricky, but still not too complicated.</p>
<pre>multiplicand = 2048; // multiplicand = 0.5;
fixed_value = (fixed_value*multiplicand)&gt;&gt;12; // fixed_value *= multiplicand;
multiplicand = 6144; // multiplicand = 1.5;
fixed_value = (fixed_value*multiplicand)&gt;&gt;12; // fixed_value *= multiplicand;
</pre>
<p>For fractional divisions, the value will need to be multiplied by the
scale value and then divided by the dividend. Keep in mind that division by
zero would still occur if the dividend is zero.
</p><pre>dividend = 2048; // dividend = 0.5;
fixed_value = (fixed_value*4096)/dividend; // fixed_value /= dividend;
dividend = 6144; // dividend = 1.5;
fixed_value = (fixed_value*4096)/dividend; // fixed_value /= dividend;
</pre>
<h2 id="tankcontrols">Implementing Tank Controls with Fixed Point</h2>
<p>As a little exercise, this part of the chapter will go through using fixed
point math to implement tank controls. The basic jist of this is that instead
of moving the player position directly by which direction of the D-pad is
pressed, instead, left and right will adjust the angle the player is facing
while up and down moves the player forward and backward perpendicular to
where the player is facing. To do this requires using sine and cosine values
and conveniently, the GTE libraries of both SDKs feature integer based sine
and cosine functions which is exactly what's needed for this exercise.</p>
<p>In the official PsyQ or Programmer's Tool SDKs there are two integer based
sine and cosine functions which are <b>rsin()</b>/<b>rcos()</b> and
<b>csin()</b>/<b>ccos()</b>. The differences between the two is that
<b>rsin()</b>/<b>rcos()</b> takes up less code but is slower, whereas
<b>csin()</b>/<b>ccos()</b> takes up more code but is faster. PSn00bSDK on
the other hand only has one set of functions called <b>isin()/icos()</b>,
which are based on a Taylor series implementation which is both small and fast.
PSn00bSDK provides definitions for <b>rsin()</b>/<b>rcos()</b> and
<b>csin()</b>/<b>ccos()</b> that simply points to <b>isin()/icos()</b>
for compatibility with PsyQ / Programmer's Tool projects and sample code.</p><p>
</p><p>These functions also take degrees in a fixed point range of 0 to 4096
where 4096 equals to 360 degrees, so a value of 45 degrees will be
specified as 512. The value returned is also in a fixed point notation
with a scale of 4096, where 4096 equals to 1.0.</p>
<p>Working from code from the controllers chapter, rewrite the code that
defines the initial values of the player position to begin at the center
of the screen. Because the player coordinates will be in fixed point, the
screen center coordinate must be multiplied by <b>ONE</b>.</p>
<pre>pos_x = ONE*(disp[0].disp.w&gt;&gt;1);
pos_y = ONE*(disp[0].disp.h&gt;&gt;1);
</pre>
<p>Then, define a new variable for the player's angle and set the initial
value to zero.</p>
<pre>int angle;
angle = 0;
</pre>
<p>The player will be represented as a rotating triangle in this chaper, so
a simple array of vector coordinates will define the shape of the triangle.
The triangle will be rotated with, you guessed it, fixed point math as well.
</p>
<pre>SVECTOR player_tri[] =
{
{ 0, -20, 0 },
{ 10, 20, 0 },
{ -10, 20, 0 }
};
</pre>
<p>Then ditch the code for sorting <b>TILE</b> and <b>SPRT</b> primitives
and replace it with the following routine that sorts a rotating triangle.</p>
<pre>POLY_F3 *tri;
...
// Rotate the triangle coordinates based on the player's angle
// as well as apply the position
for( i=0; i&lt;3; i++ )
{
v[i].vx = (((player_tri[i].vx*ccos( angle ))
-(player_tri[i].vy*csin( angle )))&gt;&gt;12)+(pos_x&gt;&gt;12);
v[i].vy = (((player_tri[i].vy*ccos( angle ))
+(player_tri[i].vx*csin( angle )))&gt;&gt;12)+(pos_y&gt;&gt;12);
}
// Sort the player triangle
tri = (POLY_F3*)nextpri;
setPolyF3( tri );
setRGB0( tri, 255, 255, 0 );
setXY3( tri,
v[0].vx, v[0].vy,
v[1].vx, v[1].vy,
v[2].vx, v[2].vy );
addPrim( ot[db], tri );
nextpri += sizeof(POLY_F3);
</pre>
<p>And then replace the input code with the following. If you've written
something that played like Asteroids in the past, this may look pretty
familiar.</p>
<pre>if( !(pad-&gt;btn&amp;PAD_UP) ) // test UP
{
pos_x += csin( angle );
pos_y -= ccos( angle );
}
else if( !(pad-&gt;btn&amp;PAD_DOWN) ) // test DOWN
{
pos_x -= csin( angle );
pos_y += ccos( angle );
}
if( !(pad-&gt;btn&amp;PAD_LEFT) ) // test LEFT
{
// Turns counter-clockwise
angle -= 16;
}
else if( !(pad-&gt;btn&amp;PAD_RIGHT) ) // test RIGHT
{
// Turns clockwise
angle += 16;
}
</pre>
<p>Next is to finally add some text drawing so the player coordinates can be
displayed on screen, so you can see how fixed point numbers work while
interacting with the sample program more easily. This can be done with the
debug font functions provided by <h>libetc</h> or <h>psxetc</h> in both
PsyQ / Programmer's Tool and PSn00bSDK respectively. These font functions are
intended for debugging purposes, so they're not fit for drawing things like
player status with custom fonts and lower case letters.</p>
<p>Start by loading the debug font texture to VRAM using <b>FntLoad()</b>,
then, initialize a font window using <b>FntOpen()</b>. Ideally, you should
put these calls inside the <b>init()</b> function.</p>
<pre>// Load the font texture on the upper-right corner of the VRAM
FntLoad( 960, 0 );
// Define a font window of 100 characters covering the whole screen
FntOpen( 0, 8, 320, 224, 0, 100 );
</pre>
<p>Text can be printed using <b>FntPrint()</b> which works more or less like
<b>printf()</b>, only text output is directed to the specified font window.
The first argument specifies which font window the text should go to, the
value of which is obtained through the return value of <b>FntOpen()</b>.
Specifying -1 directs text to the last opened font window. The debug font
routines can only draw uppercase text, and text color and font cannot be
customized.</p>
<p>In PsyQ / Programmers tool the first argument can be omitted, but modern
GNU GCC does not support this convention anymore.</p>
<pre>// Print player coordinates
FntPrint( -1, "POS_X=%d (%d.%d)\n", pos_x, (pos_x&gt;&gt;12), (pos_x&amp;0xfff) );
FntPrint( -1, "POS_Y=%d (%d.%d)\n", pos_y, (pos_y&gt;&gt;12), (pos_y&amp;0xfff) );
FntPrint( -1, "ANGLE=%d\n", angle );
</pre>
<p>Then to make the text actually appear, call <b>FntFlush()</b> to draw the
characters 'printed' by <b>FntPrint()</b> and flush the character buffer.
This should be called immediately before the <b>display()</b> call in the
sample code.</p>
<pre>// Draw and flush the character buffer
FntFlush( -1 );
</pre>
<p>The finished code should look like the following (the texture stuff
remains for future samples):</p>
<pre>#include &lt;sys/types.h&gt; // This provides typedefs needed by libgte.h and libgpu.h
#include &lt;stdio.h&gt; // Not necessary but include it anyway
#include &lt;psxetc.h&gt; // Includes some functions that controls the display
#include &lt;psxgte.h&gt; // GTE header, not really used but libgpu.h depends on it
#include &lt;psxgpu.h&gt; // GPU library header
#include &lt;psxapi.h&gt;
#define OTLEN 8 // Ordering table length (recommended to set as a define
// so it can be changed easily)
DISPENV disp[2]; // Display/drawing buffer parameters
DRAWENV draw[2];
int db = 0;
// PSn00bSDK requires having all u_long types replaced with
// u_int, as u_long in modern GCC that PSn00bSDK uses defines it as a 64-bit integer.
u_int ot[2][OTLEN]; // Ordering table length
char pribuff[2][32768]; // Primitive buffer
char *nextpri; // Next primitive pointer
int tim_mode; // TIM image parameters
RECT tim_prect,tim_crect;
int tim_uoffs,tim_voffs;
// Pad stuff
#define PAD_SELECT 1
#define PAD_L3 2
#define PAD_R3 4
#define PAD_START 8
#define PAD_UP 16
#define PAD_RIGHT 32
#define PAD_DOWN 64
#define PAD_LEFT 128
#define PAD_L2 256
#define PAD_R2 512
#define PAD_L1 1024
#define PAD_R1 2048
#define PAD_TRIANGLE 4096
#define PAD_CIRCLE 8192
#define PAD_CROSS 16384
#define PAD_SQUARE 32768
typedef struct _PADTYPE
{
unsigned char stat;
unsigned char len:4;
unsigned char type:4;
unsigned short btn;
unsigned char rs_x,rs_y;
unsigned char ls_x,ls_y;
} PADTYPE;
u_char padbuff[2][34];
// For the player triangle
SVECTOR player_tri[] = {
{ 0, -20, 0 },
{ 10, 20, 0 },
{ -10, 20, 0 }
};
void display() {
DrawSync(0); // Wait for any graphics processing to finish
VSync(0); // Wait for vertical retrace
PutDispEnv(&amp;disp[db]); // Apply the DISPENV/DRAWENVs
PutDrawEnv(&amp;draw[db]);
SetDispMask(1); // Enable the display
DrawOTag(ot[db]+OTLEN-1); // Draw the ordering table
db = !db; // Swap buffers on every pass (alternates between 1 and 0)
nextpri = pribuff[db]; // Reset next primitive pointer
}
// Texture upload function
void LoadTexture(u_int *tim, TIM_IMAGE *tparam) {
// Read TIM parameters (PsyQ)
//OpenTIM(tim);
//ReadTIM(tparam);
// Read TIM parameters (PSn00bSDK)
GetTimInfo(tim, tparam);
// Upload pixel data to framebuffer
LoadImage(tparam-&gt;prect, tparam-&gt;paddr);
DrawSync(0);
// Upload CLUT to framebuffer if present
if( tparam-&gt;mode &amp; 0x8 ) {
LoadImage(tparam-&gt;crect, tparam-&gt;caddr);
DrawSync(0);
}
}
void loadstuff(void) {
TIM_IMAGE my_image; // TIM image parameters
extern u_int tim_my_image[];
// Load the texture
LoadTexture(tim_my_image, &amp;my_image);
// Copy the TIM coordinates
tim_prect = *my_image.prect;
tim_crect = *my_image.crect;
tim_mode = my_image.mode;
// Calculate U,V offset for TIMs that are not page aligned
tim_uoffs = (tim_prect.x%64)&lt;&lt;(2-(tim_mode&amp;0x3));
tim_voffs = (tim_prect.y&amp;0xff);
}
// To make main look tidy, init stuff has to be moved here
void init(void) {
// Reset graphics
ResetGraph(0);
// First buffer
SetDefDispEnv(&amp;disp[0], 0, 0, 320, 240);
SetDefDrawEnv(&amp;draw[0], 0, 240, 320, 240);
// Second buffer
SetDefDispEnv(&amp;disp[1], 0, 240, 320, 240);
SetDefDrawEnv(&amp;draw[1], 0, 0, 320, 240);
draw[0].isbg = 1; // Enable clear
setRGB0(&amp;draw[0], 63, 0, 127); // Set clear color (dark purple)
draw[1].isbg = 1;
setRGB0(&amp;draw[1], 63, 0, 127);
nextpri = pribuff[0]; // Set initial primitive pointer address
// load textures and possibly other stuff
loadstuff();
// set tpage of lone texture as initial tpage
draw[0].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
draw[1].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
// apply initial drawing environment
PutDrawEnv(&amp;draw[!db]);
// Initialize the pads
InitPAD( padbuff[0], 34, padbuff[1], 34 );
// Begin polling
StartPAD();
// To avoid VSync Timeout error, may not be defined in PsyQ
ChangeClearPAD( 1 );
// Load the font texture on the upper-right corner of the VRAM
FntLoad( 960, 0 );
// Define a font window of 100 characters covering the whole screen
FntOpen( 0, 8, 320, 224, 0, 100 );
}
int main() {
int i;
int pos_x,pos_y,angle;
PADTYPE *pad;
POLY_F3 *tri;
SVECTOR v[3];
TILE *tile; // Pointer for TILE
SPRT *sprt; // Pointer for SPRT
// Init stuff
init();
pos_x = ONE*(disp[0].disp.w&gt;&gt;1);
pos_y = ONE*(disp[0].disp.h&gt;&gt;1);
angle = 0;
while(1) {
// Parse controller input
pad = (PADTYPE*)padbuff[0];
// Only parse inputs when a controller is connected
if( pad-&gt;stat == 0 )
{
// Only parse when a digital pad,
// dual-analog and dual-shock is connected
if( ( pad-&gt;type == 0x4 ) ||
( pad-&gt;type == 0x5 ) ||
( pad-&gt;type == 0x7 ) )
{
if( !(pad-&gt;btn&amp;PAD_UP) ) // test UP
{
pos_x += csin( angle );
pos_y -= ccos( angle );
}
else if( !(pad-&gt;btn&amp;PAD_DOWN) ) // test DOWN
{
pos_x -= csin( angle );
pos_y += ccos( angle );
}
if( !(pad-&gt;btn&amp;PAD_LEFT) ) // test LEFT
{
angle -= 16;
}
else if( !(pad-&gt;btn&amp;PAD_RIGHT) ) // test RIGHT
{
angle += 16;
}
}
}
ClearOTagR(ot[db], OTLEN); // Clear ordering table
// Rotate the triangle coordinates based on the player's angle
// as well as apply the position
for( i=0; i&lt;3; i++ )
{
v[i].vx = (((player_tri[i].vx*icos( angle ))
-(player_tri[i].vy*csin( angle )))&gt;&gt;12)+(pos_x&gt;&gt;12);
v[i].vy = (((player_tri[i].vy*icos( angle ))
+(player_tri[i].vx*csin( angle )))&gt;&gt;12)+(pos_y&gt;&gt;12);
}
// Sort the player triangle
tri = (POLY_F3*)nextpri;
setPolyF3( tri );
setRGB0( tri, 255, 255, 0 );
setXY3( tri,
v[0].vx, v[0].vy,
v[1].vx, v[1].vy,
v[2].vx, v[2].vy );
addPrim( ot[db], tri );
nextpri += sizeof(POLY_F3);
// Print player coordinates
FntPrint( -1, "POS_X=%d (%d.%d)\n", pos_x, (pos_x&gt;&gt;12), (pos_x&amp;0xfff) );
FntPrint( -1, "POS_Y=%d (%d.%d)\n", pos_y, (pos_y&gt;&gt;12), (pos_y&amp;0xfff) );
FntPrint( -1, "ANGLE=%d\n", angle );
// Draw and flush the character buffer
FntFlush( -1 );
// Update the display
display();
}
return 0;
}
</pre>
<p>Compile and execute the code and you should get a triangle that controls
more or less like a tank. Press the left and right directional buttons to
turn the triangle while pressing up and down moves the triangle forwards and
backward perpendicular to where the triangle is pointing.</p>
<center>
<img src="Chapter%201.5%20Fixed%20point%20Math_files/tankmove.png">
</center>
<h2 id="asteroids">Asteroids Style Physics with Fixed Point</h2>
<p>Now to make the tank controls sample a little more interesting by making
it control like an Asteroids or Spacewar game. Basically, instead of
accumulating the player coordinates directly with values based on the
player's angle you accumulate them to a velocity vector, which in turn
accumulates on the player's coordinates. This way, simple momentum based
physics are archieved.</p>
<p>This can be done by implementing some changes to the last sample. Start
by adding variables in <b>main()</b> that'll be used to store the player's
velocity coordinates.</p>
<pre>int vel_x,vel_y;
...
// just to make sure they don't contain garbage
vel_x = 0;
vel_y = 0;
</pre>
<p>Next, modify some of the pad code to accumulate player movement
towards the velocity variables instead of the player's coordinates.
Put some bit shifts that divides the sin/cos values by 8 otherwise
the 'ship' will accelerate too quickly.</p>
<pre>if( !(pad-&gt;btn&amp;PAD_UP) ) // test UP
{
vel_x += csin( angle )&gt;&gt;3;
vel_y -= ccos( angle )&gt;&gt;3;
}
else if( !(pad-&gt;btn&amp;PAD_DOWN) ) // test DOWN
{
vel_x -= csin( angle )&gt;&gt;3;
vel_y += ccos( angle )&gt;&gt;3;
}
</pre>
<p>Immediately after the pad code add a few lines that accumulates the
velocity coordinates to the player's coordinates.</p>
<pre>// accumulate player coordinates by its velocity
pos_x += vel_x;
pos_y += vel_y;
</pre>
<p>And to keep the player from going off-screen, place the following lines
immediately after the above code to wrap the player's coordinates when they
go off-screen.</p>
<pre>// wrap player coordinates from going off-screen
if( (pos_x&gt;&gt;12) &lt; 0 )
{
pos_x += (320&lt;&lt;12);
}
if( (pos_x&gt;&gt;12) &gt; 320 )
{
pos_x -= (320&lt;&lt;12);
}
if( (pos_y&gt;&gt;12) &lt; 0 )
{
pos_y += (240&lt;&lt;12);
}
if( (pos_y&gt;&gt;12) &gt; 240 )
{
pos_y -= (240&lt;&lt;12);
}
</pre>
<p>Then place some additional <b>FntPrint()</b> calls that displays the
values from the velocity variables. You'll also need to increase the
character buffer size of the <b>FntOpen()</b> call (the last argument)
from 100 to 150.</p>
<pre>FntPrint( -1, "VEL_X=%d (%d.%d)\n", vel_x, (vel_x&gt;&gt;12), (vel_x&amp;0xfff) );
FntPrint( -1, "VEL_Y=%d (%d.%d)\n", vel_y, (vel_y&gt;&gt;12), (vel_y&amp;0xfff) );
</pre>
<p>Compile the sample demo and the triangle should behave a lot like an
Asteroids ship.</p>
<center>
<img src="Chapter%201.5%20Fixed%20point%20Math_files/velocitymove.png">
</center>
<p>If you want velocity to slowly diminish overtime, add the following
lines just before the velocity vectors are accumulated to the player
coordinates. It also acts as a velocity constraint as well.</p>
<pre>// equivalent to multiplying each axis by 0.9765625
vel_x = (vel_x*4000)&gt;&gt;12;
vel_y = (vel_y*4000)&gt;&gt;12;
</pre>
<h2 id="spriterot">Bonus: Fixed Point Sprite Rotation</h2>
<p>Since it is something new programmers would find incredibly handy and to
show off some of what the 32-bit console can do, especially for PSn00bSDK folk
as it does not have an equivalent to libgs, here's a fixed point based sprite
rotation and scaling routine that draws a rotated and scaled sprite with a
single quad. The math for rotation is more or less the same as how the player
triangle is rotated.</p>
<pre>void sortRotSprite( int x, int y, int pw, int ph, int angle, int scale )
{
POLY_FT4 *quad;
SVECTOR s[4];
SVECTOR v[4];
int i,cx,cy;
// calculate the pivot point (center) of the sprite
cx = pw&gt;&gt;1;
cy = ph&gt;&gt;1;
// increment by 0.5 on the bottom and right coords so scaling
// would increment a bit smoother
s[0].vx = -(((pw*scale)&gt;&gt;12)-cx);
s[0].vy = -(((ph*scale)&gt;&gt;12)-cy);
s[1].vx = (((pw*scale)+2048)&gt;&gt;12)-cx;
s[1].vy = s[0].vy;
s[2].vx = -(((pw*scale)&gt;&gt;12)-cx);
s[2].vy = (((ph*scale)+2048)&gt;&gt;12)-cy;
s[3].vx = (((pw*scale)+2048)&gt;&gt;12)-cx;
s[3].vy = s[2].vy;
// a simple but pretty effective optimization trick
cx = ccos( angle );
cy = csin( angle );
// calculate rotated sprite coordinates
for( i=0; i&lt;4; i++ )
{
v[i].vx = (((s[i].vx*cx)
-(s[i].vy*cy))&gt;&gt;12)+x;
v[i].vy = (((s[i].vy*cx)
+(s[i].vx*cy))&gt;&gt;12)+y;
}
// initialize the quad primitive for the sprite
quad = (POLY_FT4*)nextpri;
setPolyFT4( quad );
// set CLUT and tpage to the primitive
setTPage( quad, tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
setClut( quad, tim_crect.x, tim_crect.y );
// set color, screen coordinates and texture coordinates of primitive
setRGB0( quad, 128, 128, 128 );
setXY4( quad,
v[0].vx, v[0].vy,
v[1].vx, v[1].vy,
v[2].vx, v[2].vy,
v[3].vx, v[3].vy );
setUVWH( quad, tim_uoffs, tim_voffs, pw, ph );
// add it to the ordering table
addPrim( ot[db], quad );
nextpri += sizeof(POLY_FT4);
}
</pre>
<p>By this point, it should be easy to figure out how to use this function
in the sample above. The <i>angle</i> and <i>scale</i> arguments are of a
fixed point notation, where 4096 is 360 degrees on the former and 4096 is
1.0 on the latter.</p>
<center>
<img src="Chapter%201.5%20Fixed%20point%20Math_files/rotscalesprite.png">
</center>
<h2 id="limitations">Limitations of Fixed Point Math</h2>
<p>One limitation that becomes apparent when performing 32-bit fixed point
math arithmetic is when performing fractional multiplication operations with
large fixed point values due to the C compiler usually always performing
multiplication and bit shifting operations with 32-bit registers, as
multiplying a large fixed point value by a large fixed point multiplicand
will likely exceed the capacity of a 32-bit word, yielding a faulty
result.</p>
<p>The MIPS R3000 CPU of the PlayStation can actually return a 64-bit
multiplication result, but the C compiler doesn't really make use of this
trait when performing multiplication operations with 32-bit integers. So the
only way to effectively take advantage of this is to use some in-line
assembly code. Should be pretty self explanatory on how and where it should
be used.</p>
<pre>/* in-line assembly macro for performing multiplication */
/* operations with 12-bit fractions. Uses what is effectively */
/* 64-bit maths with both hi and lo result registers to avoid */
/* overflow bugs when using 32-bit maths. */
/* */
/* Performs r2 = ( r0 * r1 )&gt;&gt;12 with 64-bit arithmetic */
/* */
#define mult12( r0, r1, r2 ) __asm__ volatile ( \
"mult %1, %0;" /* multiply values (small * large is faster) */\
"mflo $t0;" /* retrieve the 64-bit result in two regs */\
"mfhi $t1;" \
"srl $t0, 12;" /* equivalent to dividing LO by 4096 */\
"and $t1, 0x0fff;" /* mask HI result to fit in upper 12 bits of */\
"sll $t1, 20;" /* LO result, then shift bits to position */\
"or $t0, $t1;" /* combine the bits */\
"sw $t0, ( %2 );" /* store the result to r2 */\
: \
: "r"( r0 ), "r"( r1 ), "r"( r2 ) \
: "lo", "hi", "t0", "t1", "memory" )
</pre>
<p>Though naturally, fixed point math can't really be as precise as floating
point math in certain operations. You can try increasing precision by
increasing the base value, alloting more bits for the fractional part of a
fixed point value, but there will still be something rough about it.</p>
<h2 id="conclusion">Conclusion and Further Reading</h2>
<p>This chapter only really covers some pretty basic but highly essential math
operations with fixed point math, but it should be enough to get you started
in learning the practice. Interestingly fixed point math is still somewhat
talked about around the modern Internet, so you may want to look around for
those for further reading if need-be.</p>
<hr>
<table width="100%">
<tbody><tr>
<td width="40%" align="left"><a href="http://lameguy64.net/tutorials/pstutorials/chapter1/4-controllers.html">Previous</a></td>
<td width="20%" align="center"><a href="http://lameguy64.net/tutorials/pstutorials/index.html">Back to Index</a></td>
<td width="40%" align="right"><a href="http://lameguy64.net/tutorials/pstutorials/chapter1/6-cdreading.html">Next</a></td>
</tr>
</tbody></table>
</body></html>

49
Docs/Chapter 1.5 Fixed point Math_files/style.css

@ -0,0 +1,49 @@
body {
max-width: 900px;
margin: auto;
padding: 8px;
font-family: sans-serif;
font-size: 14px;
//color: white;
//background: black;
}
h {
background-color: #e0e0e0;
padding: 2px;
}
h2 {
border-bottom: 1px solid;
//padding-left: 8px;
}
img {
display: block;
}
.footer-table {
font-size: 14px;
}
.bordered-table {
border-collapse: collapse;
font-size: 11px;
}
.bordered-table th, .bordered-table td {
border: 1px solid;
padding: 4px;
}
hr {
border: none;
border-bottom: 1px solid black;
}
pre {
padding: 8px;
font-size: 12px;
color: black;
background-color: LightGray;
}

807
Docs/Chapter 1.6 Using the CD-ROM.htm

@ -0,0 +1,807 @@
<html><head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="Chapter%201.6%20Using%20the%20CD-ROM_files/style.css">
<title>Chapter 1.6: Using the CD-ROM</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
</head>
<body>
<h1>Chapter 1.6: Using the CD-ROM</h1>
<p>So you've managed to make it this far in this tutorial series and have
wrapped your head around uploading textures to VRAM, drawing sprite
primitives with the GPU, handling controller input and rotating sprites
using fixed-point integer math, you should be good to go at making a simple
game with the knowledge you've gained so far. However, there's one more thing
to learn that's very important to know in this endeavor before going forward
and that is using the CD-ROM.</p>
<p>The most obvious use of the CD-ROM drive on the PlayStation is, well, to
load data files from of course. Such files range from texture images, to
level data and even your program executable that the console loads during
the boot process. You can only go so far by including resources into your
PS-EXE as the console only has 2 megabytes worth of RAM, and more
importantly, they take up memory space that cannot be reclaimed even when
they are no longer needed (ie. texture images).</p>
<p>This chapter goes over the basic usage and operation of the CD-ROM library
for reading files from the CD-ROM.</p>
<p><b>Compatible with PSn00bSDK:</b> Yes</p>
<h2>Tutorial Index</h2>
<ul>
<li><a href="#workins">Workings of the CD-ROM</a></li>
<li><a href="#waystoaccess">Ways of Accessing the CD-ROM</a></li>
<li><a href="#usinglib">Using the CD-ROM Library</a></li>
<li><a href="#implementation">Implementation</a></li>
<li><a href="#makecd">Creating the CD Image</a></li>
</ul>
<h2 id="workins">Workings of the CD-ROM</h2>
<p>Before going into the know-abouts on using the CD-ROM we shall first
look into a brief explanation of how the CD-ROM format works, as
understanding some of the inner workings of the format will aid you
greatly in understanding the CD-ROM drive as you develop software for
the PlayStation.</p>
<h3>CD-ROM Structure</h3>
<p>A CD-ROM typically consists of a Table-of-Contents or TOC
and a huge spiral track that spans the entire surface of the disc containing
sectors of binary data running along the track. The TOC contains information
about the location of tracks written on the disc, their pregap and their
type of track, a track in this case being the track number to your favorite
song in a music CD. The TOC would also contain information of the next
writable location in multi-session discs, which would in turn contain
another TOC of the next session but this only really applies to CD-R
discs.</p>
<p>PlayStation game discs typically contain only one track, with the exception
of games, usually early titles, using Red Book CD Audio tracks for music
immediately after the first data track of the disc.</p>
<h3>CD-ROM Sectors</h3>
<p>A CD-ROM sector is a small data block of 2352 bytes but this only
applies to plain CD audio tracks, as the usable sector size is reduced
to 2048 bytes for data storage (ie. files). The remaining space of the
CD-ROM sector is taken up by sync and address bytes used to allow for
precise logical block addressing of the disc, alongside error detection
and correcting codes to help maintain data integrity of each data sector.
This sector format is known as Mode1, with a similar format used by the
PlayStation being Mode2/Form1 from the CD-ROM XA specification as used
by the Philips CD-i.</p>
<p>As far as the PlayStation is concerned, the console only reads
the data part of the sector on data reads, with the sync/address
and EDC/ECC correction handled transparently by the hardware
unless instructed to ignore EDC/ECC correction on data reads or
to read whole sectors including their EDC/ECC data.</p>
<h3>CD-ROM XA Extensions</h3>
<p>As the PlayStation inherits the CD-ROM XA features from the CD-i as Sony
co-developed the Green Book standard with Philips, the console supports
playing back of special ADPCOM compressed audio tracks, most commonly known
as XA audio.</p>
<p>XA audio are basically special audio tracks compressed using ADPCM, with
a maximum sample rate of 37.8KHz mono or stereo. Unlike regular Red Book CD
Audio tracks XA audio tracks are interleaved with eight different audio
tracks at once (the interleave can be doubled, tripled and quadrupled by
using mono and/or 18.9KHz sample rate) and is played at double the speed of
plain CD Audio. However, the hardware only supports playing one audio
channel at a time.</p>
<p>This has some advantages, for one the drive does not need to change speed
when going from audio playback to data reading which can help improve load
times. Secondly, XA audio tracks take up less space overall especially when
the XA audio data is laid out properly (ie. all audio channels are of roughly
the same length to one another). Thirdly, XA audio data can be interleaved
with data sectors, and is used for video playback. The Data/XA Audio interleave
also explains why some files on a PlayStation game disc (usually .STR video
files) cannot be accessed directly under most computer operating systems,
usually resulting in read errors.</p>
<p>However, XA audio has one downside and that is it tends to skip during
normal playback more than when playing back regular CD Audio tracks.</p>
<p>There is one more feature of XA audio that's seldom used and that is
channel switching during playback. This would be useful for adding dynamic
music to a game by switching to different channels of different tangents
of a level theme depending on the area the player is currently at. One game
that makes use of this feature is Klonoa: Door to Phantomile.</p>
<h3>The 650MB Limit</h3>
<p>Even though the PlayStation can read 700MB discs it cannot read more
than 650MB of the disc as the console's CD-ROM controller does not take
larger discs into account, as the console was designed before such discs
ever existed and the original CD-ROM specification specifies 650MB as the
standard capacity.</p>
<h2 id="waystoaccess">Ways of Accessing the CD-ROM</h2>
<p>There are two possible methods for accessing the CD-ROM of the PlayStation
that will work on both PsyQ/Programmer's Tool and PSn00bSDK. The first method
and one that is seldom used is the CD-ROM functions included in the console's
BIOS, which consists of calling <b>_96_init()</b> to initialize the BIOS
CD-ROM subsystem and using the BIOS file I/O functions such as <b>open()</b>
and <b>read()</b> with the <h>cdrom:</h> device name. Whilst this method is
technically the most efficient option as it does not introduce any code
overhead to your PlayStation project as the functions already reside in the
console itself, the BIOS CD-ROM functions are rather limited and in a good
number of cases, unstable.</p>
<p>For one, calling <b>_96_init()</b> clears all but the DMA channel for the
CD-ROM controller, breaking the GPU library unless you call the function before
<b>ResetGraph()</b>. The BIOS functions are also quite slow and does not
support asynchronous reads, even though the hardware itself clearly supports
such operations. It does not even support playing CD Audio nor XA audio tracks
directly, so a different method is often most desired.</p>
<p>The other, more preferable method is to use the CD-ROM library called
<h>libcd</h> in PsyQ/Programmer's Tool and <h>psxcd</h> in PSn00bSDK
respectively. Not only is it faster and more stable than the BIOS CD-ROM
functions at the cost of some overhead, but it also offers greater control
of the CD-ROM hardware as well. Playing CD Audio and XA audio included.</p>
<h2 id="usinglib">Using the CD-ROM Library</h2>
<p>Using the CD-ROM library is quite simple in principle. The first thing
to be done is to initialize the CD-ROM library by calling the function
<b>CdInit()</b>. This function not only initializes the CD-ROM hardware
but also the CD-ROM library itself.</p>
<h3 id="cdinit">Initializing the CD-ROM</h3>
<p>After calling <b>ResetGraph()</b> in your init routine you can then call
<b>CdInit()</b> to initialize the CD-ROM library.</p>
<pre>int CdInit(void)
</pre>
<p>The behavior of this function is very identical in both SDKs, but the
PsyQ/Programmers Tool implementation insists that a CD must be inserted
otherwise the function will output a lot of error messages to stdout and
fail to initialize. PSn00bSDK's implementation does not throw errors
when no disc is inserted, as it is written with utility style programs
that don't always need to read the disc in mind.</p>
<p>After calling this function, all CD-ROM functions exposed by the library
should be usable.</p>
<h3 id="locatefile">Locating a File</h3>
<p>Now that the CD-ROM library is initialized the next step is to locate a
file on the disc to be read. Unlike the BIOS CD-ROM functions, the CD-ROM
library does not have a concept of file handles and instead, files are
read directly from their logical position on the disc. Conveniently, no
files on a CD-ROM are fragmented so file read operations from the CD-ROM
are quite simple and pretty straight forward.</p>
<p>Locating a file on the disc is done by using <b>CdSearchFile()</b>.</p>
<pre>CdlFILE* CdSearchFile(const char *filename, CdlFILE *loc)
</pre>
<p>This function will search the CD-ROM file system for the file specified
by <i>filename</i> and stores information about the file, such as it's
logical position and file size, to a <b>CdlFILE</b> struct specified by
<i>loc</i>. This information is all we need to read a file from the disc.
The file name must contain an absolute path from the root directory of
the disc as the CD-ROM library has no concept of current directories. The
file path must additionally end with a file version identifier, usually
<h>;1</h>.</p>
<p>The return value is just a pointer to the struct specified by <i>loc</i>,
but NULL is returned if the file name specified does not exist.</p>
<h3 id="readfile">Reading a File</h3>
<p>Now that the file we want to read has been located, the next logical step
is to read it's contents. This is done by using two CD-ROM functions;
<b>CdControl()</b> and <b>CdRead()</b>.</p>
<p><b>CdControl()</b> is kind of a multi-purpose function as it is used
to issue raw commands directly to the console's CD-ROM controller and
can be used to make the controller do all kinds of things including
CD audio playback, but this will be covered in greater detail at a later
chapter.</p>
<p>For this instance, we'll be using <b>CdControl()</b> to issue a
<b>CdlSetloc</b> command to the CD-ROM controller with the location of the
file we just located.</p>
<pre>int CdControl(u_char com, u_char *param, u_char *result);
</pre>
<p><i>com</i> specifies the command to be issued (<b>CdlSetloc</b> in this
case) while <i>param</i> should be a pointer to the <i>loc</i> element in
the <b>CdlFILE</b> struct we obtained from the <b>CdSearchFile()</b> call
earlier. <i>result</i> can be ignored in this instance so NULL can be
specified for that argument. <i>result</i> is where return data from the
CD-ROM controller would be stored to if a small buffer is specified.</p>
<p>The reason we must issue a <b>CdlSetloc</b> command is it sets the
target location for a read, seek or play operation. The CD-ROM hardware
does not yet move it's optical pickup when <b>CdlSetloc</b> is issued
alone, seeking only occurs when either of the aforementioned disc
operations have been issued and that a target location set by issuing
<b>CdlSetloc</b> was set prior.</p>
<p>And finally, we can now start a read operation by calling the
<b>CdRead()</b> function.</p>
<pre>int CdRead(int sectors, unsigned int *buf, int mode)
</pre>
<p>As the name says it all, this function starts a data read operation from
the disc starting from the logical position specified by a previously issued
<b>CdlSetloc</b> command. <i>sectors</i> specifies the number of sectors to
read from the disc, the exact number can be determined by taking the
<i>size</i> field in the <b>CdlFILE</b> struct, adding it by 2047 then
divide by 2048. More will be explained why it had to be computed that way
later. The sectors read are then stored to <i>buf</i>, which
must point to a buffer large enough to contain all the sectors to be read.
<i>mode</i> specifies the CD-ROM mode to use for the read operation, usually
<b>CdlModeSpeed</b> is needed for all file read operations so data is read
at full speed.</p>
<p>If you haven't guessed from the brief explanation of the operation of
CD-ROMs earlier in this chapter, each sector is 2048 bytes long. And because
<b>CdRead()</b> only reads in sector units you can only read data in
multiples of 2048 bytes. The logical position of files stored on the CD-ROM
are also addressed in multiples of 2048 bytes.</p>
<p>The BIOS CD-ROM functions are also limited to reading files in units of
2048 bytes and file seeks are limited to multiples of 2048 bytes as well.
Because of this, it is much faster to just load the entirety of a file into
memory and parse the file from there, especially as performing several small
seeks and read operations would be quite slow, even moreso as the
PlayStation's CD-ROM hardware doesn't have very fast access times.</p>
<p>Once <b>CdRead()</b> has been called and the PlayStation's optical pickup
seeks to the file's location and begins reading data, the memory buffer
specified for <i>buf</i> should start filling with data from the file being
read. However, the <b>CdRead()</b> function finishes almost immediately and
the buffer may not yet contain the file you're reading yet, so another step
is required to make sure the buffer is filled with all the contents of the
file you want to load.</p>
<pre>int CdReadSync(int mode, unsigned char *result)
</pre>
<p>This function will wait until the <b>CdRead()</b> operation is actually
completed if <i>mode</i> is set to zero. If it is non-zero the function
returns the number of sectors remaining in the read operation. This is
useful if you want to have a animated loading screen or some such.
If a buffer is specified in <i>result</i> the most recent CD-ROM status
is written to that buffer, but it can be left NULL if not needed.</p>
<p>The asynchronous nature of the <b>CdRead()</b> function may be utilized
for implemented animated loading screens and such.</p>
<h3>Finished Routine</h3>
<p>With all that taken in, a simple CD-ROM read routine should like this.</p>
<pre>CdlFILE filePos;
int numsecs;
char *buff;
/* locate the file on the CD */
if( CdSearchFile( &amp;filePos, "\\TEXTURE.TIM;1" ) == NULL )
{
/* print error message if file not found */
printf( "File was not found." );
}
else
{
/* calculate number of sectors to read for the file */
numsecs = (filePos.size+2047)/2048;
/* allocate buffer for the file */
buff = (char*)malloc( 2048*numsecs );
/* set read target to the file */
CdControl( CdlSetloc, (u_char*)&amp;filePos.loc, 0 );
/* start read operation */
CdRead( numsecs, (u_long*)buff, CdlModeSpeed );
/* wait until the read operation is complete */
CdReadSync( 0, 0 );
}
</pre>
<p>You may notice that the file size has to be incremented by 2047
then divided by 2048. This is to make sure that the sector count calculated
would cover the entirety of a file that is not a perfect multiple of 2048
bytes. If the file to be read were like 1536 bytes, the whole file would be
read as one whole sector with the excess bytes being nothing more but
padding.</p>
<p>You also have to remember that data reads from the CD are still multiples
of 2048 bytes, so the read buffer must be allocated in multiples of 2048 bytes
to avoid buffer overflow bugs, which would in turn trash the memory heap.</p>
<h2 id="implementation">Implementation</h2>
<p>To keep things simple we'll just implement it on top of the exisitng
sample program from the last chapter. Basically instead of reading the
sample texture from an array we'll load the texture file from the CD-ROM.
This can be quickly implemented by implementing our CD-ROM file read routine
as a nice little function.</p>
<pre>char *loadfile( const char *filename )
{
CdlFILE filePos;
int numsecs;
char *buff;
buff = NULL;
/* locate the file on the CD */
if( CdSearchFile( filename, &amp;filePos ) == NULL )
{
/* print error message if file not found */
printf( "%s not found.", filename );
}
else
{
/* calculate number of sectors to read for the file */
numsecs = (filePos.size+2047)/2048;
/* allocate buffer for the file (replace with malloc3() for PsyQ) */
buff = (char*)malloc( 2048*numsecs );
/* set read target to the file */
CdControl( CdlSetloc, (u_char*)&amp;filePos.loc, 0 );
/* start read operation */
CdRead( numsecs, (u_long*)buff, CdlModeSpeed );
/* wait until the read operation is complete */
CdReadSync( 0, 0 );
}
return( buff );
} /* loadfile */
</pre>
<p>The sample program from the last chapter will be used to demonstrate the
usage of the function, to load the texture image from CD rather than loading
from an array. The ever growing sample program should be like this. Tweak
the code as you see fit to make it work with the SDK you're using.</p>
<pre>#include &lt;sys/types.h&gt; // This provides typedefs needed by libgte.h and libgpu.h
#include &lt;stdio.h&gt; // Not necessary but include it anyway
#include &lt;psxetc.h&gt; // Includes some functions that controls the display
#include &lt;psxgte.h&gt; // GTE header, not really used but libgpu.h depends on it
#include &lt;psxgpu.h&gt; // GPU library header
#include &lt;psxapi.h&gt;
#define OTLEN 8 // Ordering table length (recommended to set as a define
// so it can be changed easily)
DISPENV disp[2]; // Display/drawing buffer parameters
DRAWENV draw[2];
int db = 0;
// PSn00bSDK requires having all u_long types replaced with
// u_int, as u_long in modern GCC that PSn00bSDK uses defines it as a 64-bit integer.
u_int ot[2][OTLEN]; // Ordering table length
char pribuff[2][32768]; // Primitive buffer
char *nextpri; // Next primitive pointer
int tim_mode; // TIM image parameters
RECT tim_prect,tim_crect;
int tim_uoffs,tim_voffs;
// Pad stuff
#define PAD_SELECT 1
#define PAD_L3 2
#define PAD_R3 4
#define PAD_START 8
#define PAD_UP 16
#define PAD_RIGHT 32
#define PAD_DOWN 64
#define PAD_LEFT 128
#define PAD_L2 256
#define PAD_R2 512
#define PAD_L1 1024
#define PAD_R1 2048
#define PAD_TRIANGLE 4096
#define PAD_CIRCLE 8192
#define PAD_CROSS 16384
#define PAD_SQUARE 32768
typedef struct _PADTYPE
{
unsigned char stat;
unsigned char len:4;
unsigned char type:4;
unsigned short btn;
unsigned char rs_x,rs_y;
unsigned char ls_x,ls_y;
} PADTYPE;
u_char padbuff[2][34];
// For the player triangle
SVECTOR player_tri[] = {
{ 0, -20, 0 },
{ 10, 20, 0 },
{ -10, 20, 0 }
};
void display() {
DrawSync(0); // Wait for any graphics processing to finish
VSync(0); // Wait for vertical retrace
PutDispEnv(&amp;disp[db]); // Apply the DISPENV/DRAWENVs
PutDrawEnv(&amp;draw[db]);
SetDispMask(1); // Enable the display
DrawOTag(ot[db]+OTLEN-1); // Draw the ordering table
db = !db; // Swap buffers on every pass (alternates between 1 and 0)
nextpri = pribuff[db]; // Reset next primitive pointer
}
// CD loading function
char *loadfile( const char *filename )
{
CdlFILE filePos;
int numsecs;
char *buff;
buff = NULL;
/* locate the file on the CD */
if( CdSearchFile( filename, &amp;filePos ) == NULL )
{
/* print error message if file not found */
printf( "%s not found.", filename );
}
else
{
/* calculate number of sectors to read for the file */
numsecs = (filePos.size+2047)/2048;
/* allocate buffer for the file (replace with malloc3() for PsyQ) */
buff = (char*)malloc( 2048*numsecs );
/* set read target to the file */
CdControl( CdlSetloc, (u_char*)&amp;filePos.loc, 0 );
/* start read operation */
CdRead( numsecs, (u_long*)buff, CdlModeSpeed );
/* wait until the read operation is complete */
CdReadSync( 0, 0 );
}
return( buff );
} /* loadfile */
// Texture upload function
void LoadTexture(u_int *tim, TIM_IMAGE *tparam) {
// Read TIM parameters (PsyQ)
//OpenTIM(tim);
//ReadTIM(tparam);
// Read TIM parameters (PSn00bSDK)
GetTimInfo(tim, tparam);
// Upload pixel data to framebuffer
LoadImage(tparam-&gt;prect, tparam-&gt;paddr);
DrawSync(0);
// Upload CLUT to framebuffer if present
if( tparam-&gt;mode &amp; 0x8 ) {
LoadImage(tparam-&gt;crect, tparam-&gt;caddr);
DrawSync(0);
}
}
void loadstuff(void) {
TIM_IMAGE my_image; // TIM image parameters
u_int *filebuff; // Pointer for the file loaded from the disc
if( filebuff = (u_int*)loadfile( "\\TEXTURE.TIM;1" ) )
{
// On successful file read, load the texture to VRAM
LoadTexture(tim_my_image, &amp;my_image);
// Copy the TIM coordinates
tim_prect = *my_image.prect;
tim_crect = *my_image.crect;
tim_mode = my_image.mode;
// Calculate U,V offset for TIMs that are not page aligned
tim_uoffs = (tim_prect.x%64)&lt;&lt;(2-(tim_mode&amp;0x3));
tim_voffs = (tim_prect.y&amp;0xff);
// Free the file buffer
free( filebuff );
}
else
{
// Output error text that the image failed to load
printf( "Error: TEXTURE.TIM file not found.\n" );
}
}
// To make main look tidy, init stuff has to be moved here
void init(void) {
// Reset graphics
ResetGraph(0);
// Initialize the CD-ROM library
CdInit();
// First buffer
SetDefDispEnv(&amp;disp[0], 0, 0, 320, 240);
SetDefDrawEnv(&amp;draw[0], 0, 240, 320, 240);
// Second buffer
SetDefDispEnv(&amp;disp[1], 0, 240, 320, 240);
SetDefDrawEnv(&amp;draw[1], 0, 0, 320, 240);
draw[0].isbg = 1; // Enable clear
setRGB0(&amp;draw[0], 63, 0, 127); // Set clear color (dark purple)
draw[1].isbg = 1;
setRGB0(&amp;draw[1], 63, 0, 127);
nextpri = pribuff[0]; // Set initial primitive pointer address
// load textures and possibly other stuff
loadstuff();
// set tpage of lone texture as initial tpage
draw[0].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
draw[1].tpage = getTPage( tim_mode&amp;0x3, 0, tim_prect.x, tim_prect.y );
// apply initial drawing environment
PutDrawEnv(&amp;draw[!db]);
// Initialize the pads
InitPAD( padbuff[0], 34, padbuff[1], 34 );
// Begin polling
StartPAD();
// To avoid VSync Timeout error, may not be defined in PsyQ
ChangeClearPAD( 1 );
// Load the font texture on the upper-right corner of the VRAM
FntLoad( 960, 0 );
// Define a font window of 100 characters covering the whole screen
FntOpen( 0, 8, 320, 224, 0, 100 );
}
int main() {
int i;
int pos_x,pos_y,angle;
PADTYPE *pad;
POLY_F3 *tri;
SVECTOR v[3];
TILE *tile; // Pointer for TILE
SPRT *sprt; // Pointer for SPRT
// Init stuff
init();
pos_x = ONE*(disp[0].disp.w&gt;&gt;1);
pos_y = ONE*(disp[0].disp.h&gt;&gt;1);
angle = 0;
while(1) {
// Parse controller input
pad = (PADTYPE*)padbuff[0];
// Only parse inputs when a controller is connected
if( pad-&gt;stat == 0 )
{
// Only parse when a digital pad,
// dual-analog and dual-shock is connected
if( ( pad-&gt;type == 0x4 ) ||
( pad-&gt;type == 0x5 ) ||
( pad-&gt;type == 0x7 ) )
{
if( !(pad-&gt;btn&amp;PAD_UP) ) // test UP
{
pos_x += csin( angle );
pos_y -= ccos( angle );
}
else if( !(pad-&gt;btn&amp;PAD_DOWN) ) // test DOWN
{
pos_x -= csin( angle );
pos_y += ccos( angle );
}
if( !(pad-&gt;btn&amp;PAD_LEFT) ) // test LEFT
{
angle -= 16;
}
else if( !(pad-&gt;btn&amp;PAD_RIGHT) ) // test RIGHT
{
angle += 16;
}
}
}
ClearOTagR(ot[db], OTLEN); // Clear ordering table
// Rotate the triangle coordinates based on the player's angle
// as well as apply the position
for( i=0; i&lt;3; i++ )
{
v[i].vx = (((player_tri[i].vx*icos( angle ))
-(player_tri[i].vy*csin( angle )))&gt;&gt;12)+(pos_x&gt;&gt;12);
v[i].vy = (((player_tri[i].vy*icos( angle ))
+(player_tri[i].vx*csin( angle )))&gt;&gt;12)+(pos_y&gt;&gt;12);
}
// Sort the player triangle
tri = (POLY_F3*)nextpri;
setPolyF3( tri );
setRGB0( tri, 255, 255, 0 );
setXY3( tri,
v[0].vx, v[0].vy,
v[1].vx, v[1].vy,
v[2].vx, v[2].vy );
addPrim( ot[db], tri );
nextpri += sizeof(POLY_F3);
// Print player coordinates
FntPrint( -1, "POS_X=%d (%d.%d)\n", pos_x, (pos_x&gt;&gt;12), (pos_x&amp;0xfff) );
FntPrint( -1, "POS_Y=%d (%d.%d)\n", pos_y, (pos_y&gt;&gt;12), (pos_y&amp;0xfff) );
FntPrint( -1, "ANGLE=%d\n", angle );
// Draw and flush the character buffer
FntFlush( -1 );
// Update the display
display();
}
return 0;
}
</pre>
<h2 id="makecd">Creating the CD Image</h2>
<p>Once you've got the code above compiled it won't do jack for now as it
doesn't yet have a CD to read the texture file from. This is where disc
image creation comes to play in this chapter.</p>
<p>In the old days, the only preferred way to create PlayStation CD images
was with the old, MS-DOS based BUILDCD tool from the old leaked PsyQ SDK
dump. This tool is quite difficult to use on modern computers these days
largely due to being a 16-bit MS-DOS program, and while Dosbox can be used
to get it going on a modern machine it is not exactly ideal, not to mention
is very slow.</p>
<p>To make image creation even more tedious with the old BUILDCD method
the resulting image file is of a special format intended for early CD
burners and special disc cutters, so another tool called STRIPISO is
used to convert the image file to that of a usable file format. However,
the conversion process does not convert the Table-of-Contents data
produced by BUILDCD as well, so having multiple tracks in the disc image
was not possible with this method.</p>
<p>While other, more conventional means of disc image creation like
MKISOFS would work, it is not exactly ideal for projects that use XA
audio or streaming data which require support for mixed Mode2/Form1
and Mode2/Form2 not supported by MKISOFS so you'd be stuck with having
to use BUILDCD in the old days. Well... That is until
<a href="https://github.com/lameguy64/mkpsxiso">MKPSXISO</a> by
yours truly came about, solving this disc image creation dilemma in the
PlayStation homebrew scene once and for all. Said tool was so useful that
it got used quite extensively around ROM hacking and game translation
groups... Or so I heard.</p>
<h3>Creating a MKPSXISO Script</h3>
<p>Kind of like BUILDCD, MKPSXISO uses a simple script system to define
the contents and layout of a CD image. However, it uses a XML based
format similar to that you'd find in HTML webpage files, of which, in
of itself is quite simple especially if you use a good text editor
such as Notepad++ or nedit.</p>
<p>The following is a link to a sample XML script for this tutorial.
You must save the link as a file as otherwise your browser's going to
treat it as a web page. The file also contains comments that explains
the usage of the XML file.</p>
<a href="http://lameguy64.net/tutorials/pstutorials/chapter1/mkpsxiso-sample.xml">MKPSXISO Sample Script</a>
<p>The script file assumes that the above C program is compiled as
<b>cdread.exe</b>.</p>
<h3>Creating the SYSTEM.CNF File</h3>
<p>Before the ISO image can be created, a <b>SYSTEM.CNF</b> file must be
created and is a standard requirement for PlayStation game discs to include.
The <b>SYSTEM.CNF</b> file is a simple text file that defines a few
parameters. The most important being the <b>BOOT</b> variable.</p>
<pre>BOOT=cdrom:\cdread.exe;1
TCB=4
EVENT=10
STACK=801FFFF0
</pre>
<p>The parameters that immediately follow it <b>TCB</b>, <b>EVENT</b> and
<b>STACK</b> are special parameters that change the way how the kernel
is set up for the game. The parameters in the sample script are typical
values used in most games, so they can be left alone.</p>
<p>Save the text file as <b>SYSTEM.TXT</b> as the script provided will
rename it as <b>SYSTEM.CNF</b> as the disc image gets created. This is
done so that editing the CNF file is made easier when need-be, such as
changing the executable name.</p>
<h3>Creating the disc image</h3>
<p>Building the disc image with MKPSXISO is just a matter of simply
invoking it from the command line with the XML script as the argument.
</p><pre>mkpsxiso mkpsxiso-sample.xml
</pre>
<p>If things go accordingly you should end up with a BIN/CUE image pair
named <b>cdtutorial</b>. Run the disc image in your preferred emulator
and the program from the last tutorial should work now, only there's now
a slight delay from loading data from the disc.</p>
<center>
<img src="Chapter%201.6%20Using%20the%20CD-ROM_files/rotscalesprite.png">
</center>
<h2>Conclusion</h2>
<p>Hopefully this chapter has cleared up a lot of things in regards to
reading data from the CD, something I feel is still not explained very
well. But then I haven't really kept up with the PlayStation homebrew
scene in a very long while. In the future, stuff like CD Audio and XA
audio playback will be covered.</p>
<p>And this concludes the basics chapter of this tutorial series, and
if you've managed to reach this far after reading the first few chapters
you should be able to do quite a bit with 2D stuff on the console now...
Provided you managed to absorb it all.</p>
<hr>
<table width="100%">
<tbody><tr>
<td width="40%" align="left"><a href="http://lameguy64.net/tutorials/pstutorials/chapter1/5-fixedpoint.html">Previous</a></td>
<td width="20%" align="center"><a href="http://lameguy64.net/tutorials/pstutorials/index.html">Back to Index</a></td>
<td width="40%" align="right"></td>
</tr>
</tbody></table>
</body></html>

49
Docs/Chapter 1.6 Using the CD-ROM_files/style.css

@ -0,0 +1,49 @@
body {
max-width: 900px;
margin: auto;
padding: 8px;
font-family: sans-serif;
font-size: 14px;
//color: white;
//background: black;
}
h {
background-color: #e0e0e0;
padding: 2px;
}
h2 {
border-bottom: 1px solid;
//padding-left: 8px;
}
img {
display: block;
}
.footer-table {
font-size: 14px;
}
.bordered-table {
border-collapse: collapse;
font-size: 11px;
}
.bordered-table th, .bordered-table td {
border: 1px solid;
padding: 4px;
}
hr {
border: none;
border-bottom: 1px solid black;
}
pre {
padding: 8px;
font-size: 12px;
color: black;
background-color: LightGray;
}

508
Docs/Chapter 2.2 Reading a file from CD-ROM.htm

@ -0,0 +1,508 @@
<html><head><script src="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/analytics.js" type="text/javascript"></script>
<script type="text/javascript">window.addEventListener('DOMContentLoaded',function(){var v=archive_analytics.values;v.service='wb';v.server_name='wwwb-app226.us.archive.org';v.server_ms=523;archive_analytics.send_pageview({});});</script>
<script type="text/javascript" src="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/bundle-playback.js" charset="utf-8"></script>
<script type="text/javascript" src="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/wombat.js" charset="utf-8"></script>
<script type="text/javascript">
__wm.init("http://web.archive.org/web");
__wm.wombat("http://lameguy64.net/tutorials/pstutorials/chapter2-old/2-readfile.html","20220827033533","http://web.archive.org/","web","/_static/",
"1661571333");
</script>
<link rel="stylesheet" type="text/css" href="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/banner-styles.css">
<link rel="stylesheet" type="text/css" href="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/iconochive.css">
<!-- End Wayback Rewrite JS Include -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/style.css">
<title>Chapter 2.2: Reading a file from CD-ROM</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
</head>
<body><!-- BEGIN WAYBACK TOOLBAR INSERT -->
<style type="text/css">
body {
margin-top:0 !important;
padding-top:0 !important;
/*min-width:800px !important;*/
}
</style>
<script>__wm.rw(0);</script>
<div id="wm-ipp-base" style="display: block; direction: ltr;" lang="en">
</div><div id="wm-ipp-print">The Wayback Machine -
http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter2-old/2-readfile.html</div>
<script type="text/javascript">//<![CDATA[
__wm.bt(675,27,25,2,"web","http://lameguy64.net/tutorials/pstutorials/chapter2-old/2-readfile.html","20220827033533",1996,"/_static/",["/_static/css/banner-styles.css?v=fantwOh2","/_static/css/iconochive.css?v=qtvMKcIJ"], false);
__wm.rw(1);
//]]></script>
<!-- END WAYBACK TOOLBAR INSERT -->
<header>
<h1>Chapter 2.2: Reading a file from CD-ROM</h1>
</header>
<p>This chapter details how to read a file from the CD-ROM, loading the contents
into system RAM using the CD-ROM library.</p>
<p><b>PSn00bSDK Compatible:</b> Yes</p>
<h2>Tutorial Index</h2>
<ul>
<li><a href="#cdinit">Initializing the CD-ROM</a></li>
<li><a href="#filelocate">Locating a file in the CD-ROM</a></li>
<li><a href="#reading">Reading File Contents</a></li>
<li><a href="#readfunc">Simple File Read Function</a></li>
<li><a href="#imagedemo">Image Loader Example</a></li>
<li><a href="#imagebuild">Building the ISO image</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
<h2 id="cdinit">Initializing the CD-ROM</h2>
<p>Initializing the CD-ROM library is accomplished by simply calling
<b>CdInit()</b>. This function must be called after calling <b>ResetGraph()</b>
and before any CD library related function. If you intend to use the SPU you
must call <b>SpuInit()</b> immediately before calling <b>CdInit()</b>. Once the
CD-ROM library is initialized any other CD-ROM related function can be used.</p>
<h3>SDK Difference</h3>
<p>In PsyQ/Programmers' Tool, <b>CdInit()</b> will throw a lot of CD retry
messages when no disc is inserted and may lock up. In PSn00bSDK the function
carries on like normal when no disc is inserted.</p>
<h2 id="filelocate">Locating a file in the CD-ROM</h2>
<p>The CD-ROM library does not have a concept of file handles. Instead, files
are read by locating the start position of a file through the ISO9660 file
system, seeking to it and issuing a read operation until a set number of
sectors have been read. This method of loading files from disc should not be
a problem under any circumstances as files stored in a ISO9660 file system are
never fragmented. In fact, this method of reading files may have some
advantages.</p>
<p>Locating a file on the disc is done through the <b>CdSearchFile()</b>
function, which parses through the disc's file system to locate the file
and returns a <b>CdlFILE</b> which describes information about the file found
including it's position in the disc.</p>
<pre>CdlFILE file;
// Search for the file
if( !CdSearchFile( &amp;file;, "\\MYDIR\\MYFILE.DAT;1" ) )
{
// Return value is NULL, file is not found
printf( "File not found.\n" );
return 0;
}
// When file found
printf( "File found!\n" );
</pre>
<p>The file name must be specified as a complete path from root and must use
backlash characters as directory separators (use \\ in C code). The file name
must also end with a file version number which is always ';1'. If the file is
found, it will return the pointer to the specified <b>CdlFILE</b> struct,
otherwise it would simply return NULL.</p>
<p>The <b>CdlFILE</b> struct contains a copy of the file name, file size and
most importantly, the location.</p>
<h2 id="reading">Reading File Contents</h2>
<p>Now for the interesting stuff. Reading sectors is accomplished by using
<b>CdRead()</b>. But before you start a read operation, you must first set
the location of where to start reading from. This can be done using
<b>CdControl()</b> and the <b>CdlSetloc</b> command. Use this to set the
target location of the file.</p>
<pre>char *buffer;
// Allocate a buffer for the file
buffer = (char*)malloc( 2048*((file.size+2047)/2048) );
// Set seek target (seek actually happens on CdRead())
CdControl( CdSetloc, &amp;file.loc;, 0 );
// Read sectors
CdRead( (file.size+2047)/2048, (unsigned int*)buffer, CdlModeSpeed );
// Wait until read has completed
CdReadSync( 0, 0 );
</pre>
<p>You may have noticed by now that read sizes in this chapter are described in
sector units rather than byte units. That's because the CD-ROM subsystem can
only read in sector units and the CD-ROM library is optimized for reading in
sector units rather than buffering sectors to allow for byte by byte reading
for performance reasons.</p>
<p>Data sectors are typically 2048 bytes in size so buffers where data read
from the CD would be loaded to must be multiples of 2048 bytes. The arithmetic
to snap byte sizes to the nearest sector unit is described in the pseudo code
described above.</p>
<p>Once a read operation has been issued, you must wait until reading has
completed using <b>CdReadSync()</b>. You can alternatively poll the status
asynchronously by setting the <i>mode</i> parameter to 1 to perform animations
while waiting for a long read to complete.</p>
<p>If you intend to read only a part of a file instead of a whole file in a
single read operation, be aware that you can't simply call <b>CdRead()</b>
again to read the following sectors. Instead, you must retrieve the current
location using <b>CdlGetloc</b>, set it as the seek target with <b>CdlSetloc</b>
then call <b>CdRead()</b>.</p>
<h2 id="readfunc">Simple File Read Function</h2>
<p>The examples described above can be consolidated into a single function,
which can be useful for quickly implementing a file read function for testing
purposes:</p>
<pre>u_long *load_file(const char* filename)
{
CdlFILE file;
u_long *buffer;
printf( "Reading file %s... ", filename );
// Search for the file
if( !CdSearchFile( &amp;file;, (char*)filename ) )
{
// Return value is NULL, file is not found
printf( "Not found!\n" );
return NULL;
}
// Allocate a buffer for the file
buffer = (u_long*)malloc( 2048*((file.size+2047)/2048) );
// Set seek target (seek actually happens on CdRead())
CdControl( CdlSetloc, (u_char*)&amp;file.pos;, 0 );
// Read sectors
CdRead( (file.size+2047)/2048, buffer, CdlModeSpeed );
// Wait until read has completed
CdReadSync( 0, 0 );
printf( "Done.\n" );
return buffer;
}
</pre>
<p>If you want to do asynchronous loading to do background animations, you'll
have to use the CD functions more directly.</p>
<h2 id="imagedemo">Image Loader Example</h2>
<p>For completedness, this example demonstrates loading a high resolution
24-bit TIM from CD and displaying it into the framebuffer in 24-bit color mode.
Take any image file you wish to use, scale it down to 640x480 and convert it
into a 24-bit TIM with the load position set to (0,0). Name that TIM file
<i>myimage.tim</i> for this example.</p>
<p><b>PsyQ/Programmers' Tool Version</b></p>
<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;libgte.h&gt;
#include &lt;libgpu.h&gt;
#include &lt;libetc.h&gt;
#include &lt;libcd.h&gt;
// Display environment struct
DISPENV disp;
u_long *load_file(const char* filename)
{
CdlFILE file;
u_long *buffer;
printf( "Reading file %s... ", filename );
// Search for the file
if( !CdSearchFile( &amp;file;, (char*)filename ) )
{
// Return value is NULL, file is not found
printf( "Not found!\n" );
return NULL;
}
// Allocate a buffer for the file
buffer = (u_long*)malloc( 2048*((file.size+2047)/2048) );
// Set seek target (seek actually happens on CdRead())
CdControl( CdlSetloc, (u_char*)&amp;file.pos;, 0 );
// Read sectors
CdRead( (file.size+2047)/2048, buffer, CdlModeSpeed );
// Wait until read has completed
CdReadSync( 0, 0 );
printf( "Done.\n" );
return buffer;
}
void display_picture()
{
u_long *image;
TIM_IMAGE tim;
// Load the image file
if( !(image = load_file( "\\MYIMAGE.TIM;1" )) )
{
printf( "Could not load image file.\n " );
return;
}
// Read TIM header
OpenTIM( image );
ReadTIM( &amp;tim; );
// Load image to VRAM
LoadImage( tim.prect, tim.paddr );
DrawSync( 0 );
// Enable video display
VSync( 0 );
SetDispMask( 1 );
}
void init()
{
// Reset GPU (also installs IRQ handlers which are mandatory)
ResetGraph(0);
// Init CD-ROM library
CdInit();
// Set DISPENV for 640x480 24-bit color mode
SetDefDispEnv( &amp;disp;, 0, 0, 640, 480 );
disp.isrgb24 = 1; // Enables 24-bit (cannot be used for GPU graphics)
disp.isinter = 1; // Enable interlace so hi-res will display properly
// Set display environment
PutDispEnv( &amp;disp; );
}
int main(int argc, const char *argv[])
{
// Init stuff
init();
// Load and display picture
display_picture();
// Loop for safe idling
while( 1 )
{
VSync( 0 );
}
return 0;
}
</pre>
<p><b>PSn00bSDK Version</b></p>
<pre>#include &lt;stdio.h&gt;
#include &lt;malloc.h&gt;
#include &lt;psxgpu.h&gt;
#include &lt;psxcd.h&gt;
// Display environment struct
DISPENV disp;
unsigned int *load_file(const char* filename)
{
CdlFILE file;
unsigned int *buffer;
printf( "Reading file %s... ", filename );
// Search for the file
if( !CdSearchFile( &amp;file;, (char*)filename ) )
{
// Return value is NULL, file is not found
printf( "Not found!\n" );
return NULL;
}
// Allocate a buffer for the file
buffer = (unsigned int*)malloc( 2048*((file.size+2047)/2048) );
// Set seek target (seek actually happens on CdRead())
CdControl( CdlSetloc, (unsigned char*)&amp;file.pos;, 0 );
// Read sectors
CdRead( (file.size+2047)/2048, buffer, CdlModeSpeed );
// Wait until read has completed
CdReadSync( 0, 0 );
printf( "Done.\n" );
return buffer;
}
void display_picture()
{
unsigned int *image;
TIM_IMAGE tim;
// Load the image file
if( !(image = load_file( "\\MYIMAGE.TIM;1" )) )
{
printf( "Could not load image file.\n " );
return;
}
// Read TIM header
GetTimInfo( image, &amp;tim; );
// Load image to VRAM
LoadImage( tim.prect, tim.paddr );
DrawSync( 0 );
// Enable video display
VSync( 0 );
SetDispMask( 1 );
}
void init()
{
// Reset GPU (also installs IRQ handlers which are mandatory)
ResetGraph(0);
// Init CD-ROM library
CdInit( 0 );
// Set DISPENV for 640x480 24-bit color mode
SetDefDispEnv( &amp;disp;, 0, 0, 640, 480 );
disp.isrgb24 = 1; // Enables 24-bit (cannot be used for GPU graphics)
disp.isinter = 1; // Enable interlace so hi-res will display properly
// Set display environment
PutDispEnv( &amp;disp; );
}
int main(int argc, const char *argv[])
{
// Init stuff
init();
// Load and display picture
display_picture();
// Loop for safe idling
while( 1 )
{
VSync( 0 );
}
return 0;
}
</pre>
<p>Most notable differences between the PsyQ/Programmers' Tool and PSn00bSDK
versions is the latter uses type <b>unsigned int</b> instead of <b>u_long</b>
or <b>unsigned long</b> and for good reason. Modern compilers such as GCC
7.4.0 tend to assume long to be a 64-bit integer and may cause problems when
using <b>unsigned long</b>. There's no <b>OpenTIM()</b> and <b>ReadTIM()</b>
equivalent. Instead, there's <b>GetTimInfo()</b> but this may change in the
future.</p>
<p>Make sure you've compiled the example as readfile.exe for coherency with
the rest of this chapter.</p>
<h2 id="imagebuild">Building the ISO image</h2>
<p>In the past, the only way to create proper ISO images for PS1 games is to
use a tool called BUILDCD included in leaked copies of the PsyQ SDK. The
biggest problem of using BUILDCD is it generates an image file of a special
format not supported by any burner program, so another tool has to be used
(stripiso) to convert the image file it generates into a usable ISO image.
Not only that, BUILDCD is a 16-bit DOS executable and is difficult and very
slow to use on a modern system.</p>
<p>Instead of using BUILDCD, use
<a href="http://web.archive.org/web/20220827033533/https://github.com/lameguy64/mkpsxiso">MKPSXISO</a> instead. It
offers about the same functionality as BUILDCD but better, and is built for
modern Windows and Linux platforms.</p>
<p><b>MKPSXISO Project XML</b></p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!-- Defines the ISO project --&gt;
&lt;iso_project image_name="readfile.iso"&gt;
&lt;!-- Defines the data track for this tutorial --&gt;
&lt;track type="data"&gt;
&lt;!-- Specifies identifier strings such as volume label --&gt;
&lt;!-- System and application identifiers must be PLAYSTATION --&gt;
&lt;identifiers
system ="PLAYSTATION"
application ="PLAYSTATION"
volume ="PSXTUTORIAL"
volume_set ="PSXTUTORIAL"
publisher ="MEIDOTEK"
/&gt;
&lt;!-- Defines the directory tree of the data track --&gt;
&lt;directory_tree&gt;
&lt;!-- Specify files in the directory tree --&gt;
&lt;file name="system.cnf" type="data" source="system.cnf"/&gt;
&lt;file name="readfile.exe" type="data" source="readfile.exe"/&gt;
&lt;file name="myimage.tim" type="data" source="myimage.tim"/&gt;
&lt;!-- Place dummy sectors at the end --&gt;
&lt;dummy sectors="1024"/&gt;
&lt;/directory_tree&gt;
&lt;/track&gt;
&lt;/iso_project&gt;
</pre>
<p>While on the subject of ISO image creation, you'll also need to create a
special SYSTEM.CNF file in order to make your disc image bootable. A
SYSTEM.CNF file is simply a text file that specifies the file name of the
executable, stack address, number of task and event blocks. The latter three
wouldn't be discussed in this chapter and the typical values are generally
good enough.</p>
<p><b>SYSTEM.CNF Contents</b></p>
<pre>BOOT=cdrom:\readfile.exe;1
TCB=4
EVENT=10
STACK=801FFFF0
</pre>
<p>Once your MKPSXISO project and SYSTEM.CNF files are set, execute MKPSXISO
like so to create the ISO image:</p>
<pre>mkpsxiso readfile.xml
</pre>
<p>Run the ISO image in an emulator and you should see your 24-bit TIM image
displayed. It may take awhile for the image to appear as the 24-bit TIM image
is a pretty big file to load for the PS1.</p>
<p></p>
<h2 id="conclusion">Conclusion</h2>
<p>This chapter should cover about everything you need to know to load a file
from CD-ROM. The next chapter will cover common ways to optimize CD-ROM
accesses to speed up load times in your homebrew.</p>
<hr>
<table class="footer-table" width="100%">
<tbody><tr>
<td width="40%" align="left"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter2-old/1-cdrom.html">Previous</a></td>
<td width="20%" align="center"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/index.html">Back to Index</a></td>
<td width="40%" align="right"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter2-old/3-optimizing.html">Next</a></td>
</tr>
</tbody></table>
</body></html>
<!--
FILE ARCHIVED ON 03:35:33 Aug 27, 2022 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 15:40:55 Sep 05, 2022.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
-->
<!--
playback timings (ms):
captures_list: 170.071
exclusion.robots: 0.17
exclusion.robots.policy: 0.163
RedisCDXSource: 0.884
esindex: 0.008
LoadShardBlock: 151.904 (3)
PetaboxLoader3.datanode: 200.102 (4)
CDXLines.iter: 14.739 (3)
load_resource: 348.367
PetaboxLoader3.resolve: 286.145
-->

474
Docs/Chapter 2.2 Reading a file from CD-ROM_files/analytics.js

@ -0,0 +1,474 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0
/* eslint-disable no-var, semi, prefer-arrow-callback, prefer-template */
/**
* Collection of methods for sending analytics events to Archive.org's analytics server.
*
* These events are used for internal stats and sent (in anonymized form) to Google Analytics.
*
* @see analytics.md
*
* @type {Object}
*/
window.archive_analytics = (function defineArchiveAnalytics() {
// keep orignal Date object so as not to be affected by wayback's
// hijacking global Date object
var Date = window.Date;
var ARCHIVE_ANALYTICS_VERSION = 2;
var DEFAULT_SERVICE = 'ao_2';
var NO_SAMPLING_SERVICE = 'ao_no_sampling'; // sends every event instead of a percentage
var startTime = new Date();
/**
* @return {Boolean}
*/
function isPerformanceTimingApiSupported() {
return 'performance' in window && 'timing' in window.performance;
}
/**
* Determines how many milliseconds elapsed between the browser starting to parse the DOM and
* the current time.
*
* Uses the Performance API or a fallback value if it's not available.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
*
* @return {Number}
*/
function getLoadTime() {
var start;
if (isPerformanceTimingApiSupported())
start = window.performance.timing.domLoading;
else
start = startTime.getTime();
return new Date().getTime() - start;
}
/**
* Determines how many milliseconds elapsed between the user navigating to the page and
* the current time.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
*
* @return {Number|null} null if the browser doesn't support the Performance API
*/
function getNavToDoneTime() {
if (!isPerformanceTimingApiSupported())
return null;
return new Date().getTime() - window.performance.timing.navigationStart;
}
/**
* Performs an arithmetic calculation on a string with a number and unit, while maintaining
* the unit.
*
* @param {String} original value to modify, with a unit
* @param {Function} doOperation accepts one Number parameter, returns a Number
* @returns {String}
*/
function computeWithUnit(original, doOperation) {
var number = parseFloat(original, 10);
var unit = original.replace(/(\d*\.\d+)|\d+/, '');
return doOperation(number) + unit;
}
/**
* Computes the default font size of the browser.
*
* @returns {String|null} computed font-size with units (typically pixels), null if it cannot be computed
*/
function getDefaultFontSize() {
var fontSizeStr;
if (!('getComputedStyle' in window))
return null;
var style = window.getComputedStyle(document.documentElement);
if (!style)
return null;
fontSizeStr = style.fontSize;
// Don't modify the value if tracking book reader.
if (document.querySelector('#BookReader'))
return fontSizeStr;
return computeWithUnit(fontSizeStr, function reverseBootstrapFontSize(number) {
// Undo the 62.5% size applied in the Bootstrap CSS.
return number * 1.6;
});
}
/**
* Get the URL parameters for a given Location
* @param {Location}
* @return {Object} The URL parameters
*/
function getParams(location) {
if (!location) location = window.location;
var vars;
var i;
var pair;
var params = {};
var query = location.search;
if (!query) return params;
vars = query.substring(1).split('&');
for (i = 0; i < vars.length; i++) {
pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
}
function getMetaProp(name) {
var metaTag = document.querySelector('meta[property=' + name + ']');
return metaTag ? metaTag.getAttribute('content') || null : null;
}
var ArchiveAnalytics = {
/**
* @type {String|null}
*/
service: getMetaProp('service'),
mediaType: getMetaProp('mediatype'),
primaryCollection: getMetaProp('primary_collection'),
/**
* Key-value pairs to send in pageviews (you can read this after a pageview to see what was
* sent).
*
* @type {Object}
*/
values: {},
/**
* Sends an analytics ping, preferably using navigator.sendBeacon()
* @param {Object} values
* @param {Function} [onload_callback] (deprecated) callback to invoke once ping to analytics server is done
* @param {Boolean} [augment_for_ao_site] (deprecated) if true, add some archive.org site-specific values
*/
send_ping: function send_ping(values, onload_callback, augment_for_ao_site) {
if (typeof window.navigator !== 'undefined' && typeof window.navigator.sendBeacon !== 'undefined')
this.send_ping_via_beacon(values);
else
this.send_ping_via_image(values);
},
/**
* Sends a ping via Beacon API
* NOTE: Assumes window.navigator.sendBeacon exists
* @param {Object} values Tracking parameters to pass
*/
send_ping_via_beacon: function send_ping_via_beacon(values) {
var url = this.generate_tracking_url(values || {});
window.navigator.sendBeacon(url);
},
/**
* Sends a ping via Image object
* @param {Object} values Tracking parameters to pass
*/
send_ping_via_image: function send_ping_via_image(values) {
var url = this.generate_tracking_url(values || {});
var loadtime_img = new Image(1, 1);
loadtime_img.src = url;
loadtime_img.alt = '';
},
/**
* Construct complete tracking URL containing payload
* @param {Object} params Tracking parameters to pass
* @return {String} URL to use for tracking call
*/
generate_tracking_url: function generate_tracking_url(params) {
var baseUrl = '//analytics.archive.org/0.gif';
var keys;
var outputParams = params;
var outputParamsArray = [];
outputParams.service = outputParams.service || this.service || DEFAULT_SERVICE;
// Build array of querystring parameters
keys = Object.keys(outputParams);
keys.forEach(function keyIteration(key) {
outputParamsArray.push(encodeURIComponent(key) + '=' + encodeURIComponent(outputParams[key]));
});
outputParamsArray.push('version=' + ARCHIVE_ANALYTICS_VERSION);
outputParamsArray.push('count=' + (keys.length + 2)); // Include `version` and `count` in count
return baseUrl + '?' + outputParamsArray.join('&');
},
/**
* @param {int} page Page number
*/
send_scroll_fetch_event: function send_scroll_fetch_event(page) {
var additionalValues = { ev: page };
var loadTime = getLoadTime();
var navToDoneTime = getNavToDoneTime();
if (loadTime) additionalValues.loadtime = loadTime;
if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
this.send_event('page_action', 'scroll_fetch', location.pathname, additionalValues);
},
send_scroll_fetch_base_event: function send_scroll_fetch_base_event() {
var additionalValues = {};
var loadTime = getLoadTime();
var navToDoneTime = getNavToDoneTime();
if (loadTime) additionalValues.loadtime = loadTime;
if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
this.send_event('page_action', 'scroll_fetch_base', location.pathname, additionalValues);
},
/**
* @param {Object} [options]
* @param {String} [options.mediaType]
* @param {String} [options.mediaLanguage]
* @param {String} [options.page] The path portion of the page URL
*/
send_pageview: function send_pageview(options) {
var settings = options || {};
var defaultFontSize;
var loadTime = getLoadTime();
var mediaType = settings.mediaType;
var primaryCollection = settings.primaryCollection;
var page = settings.page;
var navToDoneTime = getNavToDoneTime();
/**
* @return {String}
*/
function get_locale() {
if (navigator) {
if (navigator.language)
return navigator.language;
else if (navigator.browserLanguage)
return navigator.browserLanguage;
else if (navigator.systemLanguage)
return navigator.systemLanguage;
else if (navigator.userLanguage)
return navigator.userLanguage;
}
return '';
}
defaultFontSize = getDefaultFontSize();
// Set field values
this.values.kind = 'pageview';
this.values.timediff = (new Date().getTimezoneOffset()/60)*(-1); // *timezone* diff from UTC
this.values.locale = get_locale();
this.values.referrer = (document.referrer == '' ? '-' : document.referrer);
if (loadTime)
this.values.loadtime = loadTime;
if (navToDoneTime)
this.values.nav_to_done_ms = navToDoneTime;
if (settings.trackingId) {
this.values.ga_tid = settings.trackingId;
}
/* START CUSTOM DIMENSIONS */
if (defaultFontSize)
this.values.ga_cd1 = defaultFontSize;
if ('devicePixelRatio' in window)
this.values.ga_cd2 = window.devicePixelRatio;
if (mediaType)
this.values.ga_cd3 = mediaType;
if (settings.mediaLanguage) {
this.values.ga_cd4 = settings.mediaLanguage;
}
if (primaryCollection) {
this.values.ga_cd5 = primaryCollection;
}
/* END CUSTOM DIMENSIONS */
if (page)
this.values.page = page;
this.send_ping(this.values);
},
/**
* Sends a tracking "Event".
* @param {string} category
* @param {string} action
* @param {string} label
* @param {Object} additionalEventParams
*/
send_event: function send_event(
category,
action,
label,
additionalEventParams
) {
if (!label) label = window.location.pathname;
if (!additionalEventParams) additionalEventParams = {};
if (additionalEventParams.mediaLanguage) {
additionalEventParams.ga_cd4 = additionalEventParams.mediaLanguage;
delete additionalEventParams.mediaLanguage;
}
var eventParams = Object.assign(
{
kind: 'event',
ec: category,
ea: action,
el: label,
cache_bust: Math.random(),
},
additionalEventParams
);
this.send_ping(eventParams);
},
/**
* Sends every event instead of a small percentage.
*
* Use this sparingly as it can generate a lot of events.
*
* @param {string} category
* @param {string} action
* @param {string} label
* @param {Object} additionalEventParams
*/
send_event_no_sampling: function send_event_no_sampling(
category,
action,
label,
additionalEventParams
) {
var extraParams = additionalEventParams || {};
extraParams.service = NO_SAMPLING_SERVICE;
this.send_event(category, action, label, extraParams);
},
/**
* @param {Object} options see this.send_pageview options
*/
send_pageview_on_load: function send_pageview_on_load(options) {
var self = this;
window.addEventListener('load', function send_pageview_with_options() {
self.send_pageview(options);
});
},
/**
* Handles tracking events passed in URL.
* Assumes category and action values are separated by a "|" character.
* NOTE: Uses the unsampled analytics property. Watch out for future high click links!
* @param {Location}
*/
process_url_events: function process_url_events(location) {
var eventValues;
var actionValue;
var eventValue = getParams(location).iax;
if (!eventValue) return;
eventValues = eventValue.split('|');
actionValue = eventValues.length >= 1 ? eventValues[1] : '';
this.send_event_no_sampling(
eventValues[0],
actionValue,
window.location.pathname
);
},
/**
* Attaches handlers for event tracking.
*
* To enable click tracking for a link, add a `data-event-click-tracking`
* attribute containing the Google Analytics Event Category and Action, separated
* by a vertical pipe (|).
* e.g. `<a href="foobar" data-event-click-tracking="TopNav|FooBar">`
*
* To enable form submit tracking, add a `data-event-form-tracking` attribute
* to the `form` tag.
* e.g. `<form data-event-form-tracking="TopNav|SearchForm" method="GET">`
*
* Additional tracking options can be added via a `data-event-tracking-options`
* parameter. This parameter, if included, should be a JSON string of the parameters.
* Valid parameters are:
* - service {string}: Corresponds to the Google Analytics property data values flow into
*/
set_up_event_tracking: function set_up_event_tracking() {
var self = this;
var clickTrackingAttributeName = 'event-click-tracking';
var formTrackingAttributeName = 'event-form-tracking';
var trackingOptionsAttributeName = 'event-tracking-options';
function handleAction(event, attributeName) {
var selector = '[data-' + attributeName + ']';
var eventTarget = event.target;
if (!eventTarget) return;
var target = eventTarget.closest(selector);
if (!target) return;
var categoryAction;
var categoryActionParts;
var options;
categoryAction = target.dataset[toCamelCase(attributeName)];
if (!categoryAction) return;
categoryActionParts = categoryAction.split('|');
options = target.dataset[toCamelCase(trackingOptionsAttributeName)];
options = options ? JSON.parse(options) : {};
self.send_event(
categoryActionParts[0],
categoryActionParts[1],
categoryActionParts[2] || window.location.pathname,
options.service ? { service: options.service } : {}
);
}
function toCamelCase(str) {
return str.replace(/\W+(.)/g, function (match, chr) {
return chr.toUpperCase();
});
};
document.addEventListener('click', function(e) {
handleAction(e, clickTrackingAttributeName);
});
document.addEventListener('submit', function(e) {
handleAction(e, formTrackingAttributeName);
});
},
/**
* @returns {Object[]}
*/
get_data_packets: function get_data_packets() {
return [this.values];
},
/**
* Creates a tracking image for tracking JS compatibility.
*
* @param {string} type The type value for track_js_case in query params for 0.gif
*/
create_tracking_image: function create_tracking_image(type) {
this.send_ping_via_image({
cache_bust: Math.random(),
kind: 'track_js',
track_js_case: type,
});
}
};
return ArchiveAnalytics;
}());
// @license-end

500
Docs/Chapter 2.2 Reading a file from CD-ROM_files/banner-styles.css

@ -0,0 +1,500 @@
@import 'record.css'; /* for SPN1 */
#wm-ipp-base {
height:65px;/* initial height just in case js code fails */
padding:0;
margin:0;
border:none;
background:none transparent;
}
#wm-ipp {
z-index: 2147483647;
}
#wm-ipp, #wm-ipp * {
font-family:Lucida Grande, Helvetica, Arial, sans-serif;
font-size:12px;
line-height:1.2;
letter-spacing:0;
width:auto;
height:auto;
max-width:none;
max-height:none;
min-width:0 !important;
min-height:0;
outline:none;
float:none;
text-align:left;
border:none;
color: #000;
text-indent: 0;
position: initial;
background: none;
}
#wm-ipp div, #wm-ipp canvas {
display: block;
}
#wm-ipp div, #wm-ipp tr, #wm-ipp td, #wm-ipp a, #wm-ipp form {
padding:0;
margin:0;
border:none;
border-radius:0;
background-color:transparent;
background-image:none;
/*z-index:2147483640;*/
height:auto;
}
#wm-ipp table {
border:none;
border-collapse:collapse;
margin:0;
padding:0;
width:auto;
font-size:inherit;
}
#wm-ipp form input {
padding:1px !important;
height:auto;
display:inline;
margin:0;
color: #000;
background: none #fff;
border: 1px solid #666;
}
#wm-ipp form input[type=submit] {
padding:0 8px !important;
margin:1px 0 1px 5px !important;
width:auto !important;
border: 1px solid #000 !important;
background: #fff !important;
color: #000 !important;
}
#wm-ipp a {
display: inline;
}
#wm-ipp a:hover{
text-decoration:underline;
}
#wm-ipp a.wm-btn:hover {
text-decoration:none;
color:#ff0 !important;
}
#wm-ipp a.wm-btn:hover span {
color:#ff0 !important;
}
#wm-ipp #wm-ipp-inside {
margin: 0 6px;
border:5px solid #000;
border-top:none;
background-color:rgba(255,255,255,0.9);
-moz-box-shadow:1px 1px 4px #333;
-webkit-box-shadow:1px 1px 4px #333;
box-shadow:1px 1px 4px #333;
border-radius:0 0 8px 8px;
}
/* selectors are intentionally verbose to ensure priority */
#wm-ipp #wm-logo {
padding:0 10px;
vertical-align:middle;
min-width:100px;
flex: 0 0 100px;
}
#wm-ipp .c {
padding-left: 4px;
}
#wm-ipp .c .u {
margin-top: 4px !important;
}
#wm-ipp .n {
padding:0 0 0 5px !important;
vertical-align: bottom;
}
#wm-ipp .n a {
text-decoration:none;
color:#33f;
font-weight:bold;
}
#wm-ipp .n .b {
padding:0 6px 0 0 !important;
text-align:right !important;
overflow:visible;
white-space:nowrap;
color:#99a;
vertical-align:middle;
}
#wm-ipp .n .y .b {
padding:0 6px 2px 0 !important;
}
#wm-ipp .n .c {
background:#000;
color:#ff0;
font-weight:bold;
padding:0 !important;
text-align:center;
}
#wm-ipp.hi .n td.c {
color:#ec008c;
}
#wm-ipp .n td.f {
padding:0 0 0 6px !important;
text-align:left !important;
overflow:visible;
white-space:nowrap;
color:#99a;
vertical-align:middle;
}
#wm-ipp .n tr.m td {
text-transform:uppercase;
white-space:nowrap;
padding:2px 0;
}
#wm-ipp .c .s {
padding:0 5px 0 0 !important;
vertical-align:bottom;
}
#wm-ipp #wm-nav-captures {
white-space: nowrap;
}
#wm-ipp .c .s a.t {
color:#33f;
font-weight:bold;
line-height: 1.8;
}
#wm-ipp .c .s div.r {
color: #666;
font-size:9px;
white-space:nowrap;
}
#wm-ipp .c .k {
padding-bottom:1px;
}
#wm-ipp .c .s {
padding:0 5px 2px 0 !important;
}
#wm-ipp td#displayMonthEl {
padding: 2px 0 !important;
}
#wm-ipp td#displayYearEl {
padding: 0 0 2px 0 !important;
}
div#wm-ipp-sparkline {
position:relative;/* for positioning markers */
white-space:nowrap;
background-color:#fff;
cursor:pointer;
line-height:0.9;
}
#sparklineImgId, #wm-sparkline-canvas {
position:relative;
z-index:9012;
max-width:none;
}
#wm-ipp-sparkline div.yt {
position:absolute;
z-index:9010 !important;
background-color:#ff0 !important;
top: 0;
}
#wm-ipp-sparkline div.mt {
position:absolute;
z-index:9013 !important;
background-color:#ec008c !important;
top: 0;
}
#wm-ipp .r {
margin-left: 4px;
}
#wm-ipp .r a {
color:#33f;
border:none;
position:relative;
background-color:transparent;
background-repeat:no-repeat !important;
background-position:100% 100% !important;
text-decoration: none;
}
#wm-ipp #wm-capinfo {
/* prevents notice div background from sticking into round corners of
#wm-ipp-inside */
border-radius: 0 0 4px 4px;
}
#wm-ipp #wm-capinfo .c-logo {
display:block;
float:left;
margin-right:3px;
width:90px;
min-height:90px;
max-height: 290px;
border-radius:45px;
overflow:hidden;
background-position:50%;
background-size:auto 90px;
box-shadow: 0 0 2px 2px rgba(208,208,208,128) inset;
}
#wm-ipp #wm-capinfo .c-logo span {
display:inline-block;
}
#wm-ipp #wm-capinfo .c-logo img {
height:90px;
position:relative;
left:-50%;
}
#wm-ipp #wm-capinfo .wm-title {
font-size:130%;
}
#wm-ipp #wm-capinfo a.wm-selector {
display:inline-block;
color: #aaa;
text-decoration:none !important;
padding: 2px 8px;
}
#wm-ipp #wm-capinfo a.wm-selector.selected {
background-color:#666;
}
#wm-ipp #wm-capinfo a.wm-selector:hover {
color: #fff;
}
#wm-ipp #wm-capinfo.notice-only #wm-capinfo-collected-by,
#wm-ipp #wm-capinfo.notice-only #wm-capinfo-timestamps {
display: none;
}
#wm-ipp #wm-capinfo #wm-capinfo-notice .wm-capinfo-content {
background-color:#ff0;
padding:5px;
font-size:14px;
text-align:center;
}
#wm-ipp #wm-capinfo #wm-capinfo-notice .wm-capinfo-content * {
font-size:14px;
text-align:center;
}
#wm-ipp #wm-expand {
right: 1px;
bottom: -1px;
color: #ffffff;
background-color: #666 !important;
padding:0 5px 0 3px !important;
border-radius: 3px 3px 0 0 !important;
}
#wm-ipp #wm-expand span {
color: #ffffff;
}
#wm-ipp #wm-expand #wm-expand-icon {
display: inline-block;
transition: transform 0.5s;
transform-origin: 50% 45%;
}
#wm-ipp #wm-expand.wm-open #wm-expand-icon {
transform: rotate(180deg);
}
#wm-ipp #wmtb {
text-align:right;
}
#wm-ipp #wmtb #wmtbURL {
width: calc(100% - 45px);
}
#wm-ipp #wm-graph-anchor {
border-right:1px solid #ccc;
}
/* time coherence */
html.wb-highlight {
box-shadow: inset 0 0 0 3px #a50e3a !important;
}
.wb-highlight {
outline: 3px solid #a50e3a !important;
}
#wm-ipp-print {
display:none !important;
}
@media print {
#wm-ipp-base {
display:none !important;
}
#wm-ipp-print {
display:block !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
@media (max-width:414px) {
#wm-ipp .xxs {
display:none !important;
}
}
@media (min-width:1055px) {
#wm-ipp #wm-graph-anchor {
display:block !important;
}
}
@media (max-width:1054px) {
#wm-ipp #wm-graph-anchor {
display:none !important;
}
}
@media (max-width:1163px) {
#wm-logo {
display:none !important;
}
}
#wm-btns {
white-space: nowrap;
margin-top: -2px;
}
#wm-btns #wm-save-snapshot-open {
margin-right: 7px;
top: -6px;
}
#wm-btns #wm-sign-in {
box-sizing: content-box;
display: none;
margin-right: 7px;
top: -8px;
/*
round border around sign in button
*/
border: 2px #000 solid;
border-radius: 14px;
padding-right: 2px;
padding-bottom: 2px;
width: 11px;
height: 11px;
}
#wm-btns #wm-sign-in>.iconochive-person {
font-size: 12.5px;
}
#wm-save-snapshot-open > .iconochive-web {
color:#000;
font-size:160%;
}
#wm-ipp #wm-share {
display: flex;
align-items: flex-end;
justify-content: space-between;
}
#wm-share > #wm-screenshot {
display: inline-block;
margin-right: 3px;
visibility: hidden;
}
#wm-screenshot > .iconochive-image {
color:#000;
font-size:160%;
}
#wm-share > #wm-video {
display: inline-block;
margin-right: 3px;
visibility: hidden;
}
#wm-video > .iconochive-movies {
color: #000;
display: inline-block;
font-size: 150%;
margin-bottom: 2px;
}
#wm-btns #wm-save-snapshot-in-progress {
display: none;
font-size:160%;
opacity: 0.5;
position: relative;
margin-right: 7px;
top: -5px;
}
#wm-btns #wm-save-snapshot-success {
display: none;
color: green;
position: relative;
top: -7px;
}
#wm-btns #wm-save-snapshot-fail {
display: none;
color: red;
position: relative;
top: -7px;
}
.wm-icon-screen-shot {
background: url("../images/web-screenshot.svg") no-repeat !important;
background-size: contain !important;
width: 22px !important;
height: 19px !important;
display: inline-block;
}
#donato {
/* transition effect is disable so as to simplify height adjustment */
/*transition: height 0.5s;*/
height: 0;
margin: 0;
padding: 0;
border-bottom: 1px solid #999 !important;
}
body.wm-modal {
height: auto !important;
overflow: hidden !important;
}
#donato #donato-base {
width: 100%;
height: 100%;
/*bottom: 0;*/
margin: 0;
padding: 0;
position: absolute;
z-index: 2147483639;
}
body.wm-modal #donato #donato-base {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2147483640;
}
.wb-autocomplete-suggestions {
font-family: Lucida Grande, Helvetica, Arial, sans-serif;
font-size: 12px;
text-align: left;
cursor: default;
border: 1px solid #ccc;
border-top: 0;
background: #fff;
box-shadow: -1px 1px 3px rgba(0,0,0,.1);
position: absolute;
display: none;
z-index: 2147483647;
max-height: 254px;
overflow: hidden;
overflow-y: auto;
box-sizing: border-box;
}
.wb-autocomplete-suggestion {
position: relative;
padding: 0 .6em;
line-height: 23px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.02em;
color: #333;
}
.wb-autocomplete-suggestion b {
font-weight: bold;
}
.wb-autocomplete-suggestion.selected {
background: #f0f0f0;
}

3
Docs/Chapter 2.2 Reading a file from CD-ROM_files/bundle-playback.js
File diff suppressed because it is too large
View File

116
Docs/Chapter 2.2 Reading a file from CD-ROM_files/iconochive.css

@ -0,0 +1,116 @@
@font-face{font-family:'Iconochive-Regular';src:url('https://archive.org/includes/fonts/Iconochive-Regular.eot?-ccsheb');src:url('https://archive.org/includes/fonts/Iconochive-Regular.eot?#iefix-ccsheb') format('embedded-opentype'),url('https://archive.org/includes/fonts/Iconochive-Regular.woff?-ccsheb') format('woff'),url('https://archive.org/includes/fonts/Iconochive-Regular.ttf?-ccsheb') format('truetype'),url('https://archive.org/includes/fonts/Iconochive-Regular.svg?-ccsheb#Iconochive-Regular') format('svg');font-weight:normal;font-style:normal}
[class^="iconochive-"],[class*=" iconochive-"]{font-family:'Iconochive-Regular'!important;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
.iconochive-Uplevel:before{content:"\21b5"}
.iconochive-exit:before{content:"\1f6a3"}
.iconochive-beta:before{content:"\3b2"}
.iconochive-logo:before{content:"\1f3db"}
.iconochive-audio:before{content:"\1f568"}
.iconochive-movies:before{content:"\1f39e"}
.iconochive-software:before{content:"\1f4be"}
.iconochive-texts:before{content:"\1f56e"}
.iconochive-etree:before{content:"\1f3a4"}
.iconochive-image:before{content:"\1f5bc"}
.iconochive-web:before{content:"\1f5d4"}
.iconochive-collection:before{content:"\2211"}
.iconochive-folder:before{content:"\1f4c2"}
.iconochive-data:before{content:"\1f5c3"}
.iconochive-tv:before{content:"\1f4fa"}
.iconochive-article:before{content:"\1f5cf"}
.iconochive-question:before{content:"\2370"}
.iconochive-question-dark:before{content:"\3f"}
.iconochive-info:before{content:"\69"}
.iconochive-info-small:before{content:"\24d8"}
.iconochive-comment:before{content:"\1f5e9"}
.iconochive-comments:before{content:"\1f5ea"}
.iconochive-person:before{content:"\1f464"}
.iconochive-people:before{content:"\1f465"}
.iconochive-eye:before{content:"\1f441"}
.iconochive-rss:before{content:"\221e"}
.iconochive-time:before{content:"\1f551"}
.iconochive-quote:before{content:"\275d"}
.iconochive-disc:before{content:"\1f4bf"}
.iconochive-tv-commercial:before{content:"\1f4b0"}
.iconochive-search:before{content:"\1f50d"}
.iconochive-search-star:before{content:"\273d"}
.iconochive-tiles:before{content:"\229e"}
.iconochive-list:before{content:"\21f6"}
.iconochive-list-bulleted:before{content:"\2317"}
.iconochive-latest:before{content:"\2208"}
.iconochive-left:before{content:"\2c2"}
.iconochive-right:before{content:"\2c3"}
.iconochive-left-solid:before{content:"\25c2"}
.iconochive-right-solid:before{content:"\25b8"}
.iconochive-up-solid:before{content:"\25b4"}
.iconochive-down-solid:before{content:"\25be"}
.iconochive-dot:before{content:"\23e4"}
.iconochive-dots:before{content:"\25a6"}
.iconochive-columns:before{content:"\25af"}
.iconochive-sort:before{content:"\21d5"}
.iconochive-atoz:before{content:"\1f524"}
.iconochive-ztoa:before{content:"\1f525"}
.iconochive-upload:before{content:"\1f4e4"}
.iconochive-download:before{content:"\1f4e5"}
.iconochive-favorite:before{content:"\2605"}
.iconochive-heart:before{content:"\2665"}
.iconochive-play:before{content:"\25b6"}
.iconochive-play-framed:before{content:"\1f3ac"}
.iconochive-fullscreen:before{content:"\26f6"}
.iconochive-mute:before{content:"\1f507"}
.iconochive-unmute:before{content:"\1f50a"}
.iconochive-share:before{content:"\1f381"}
.iconochive-edit:before{content:"\270e"}
.iconochive-reedit:before{content:"\2710"}
.iconochive-gear:before{content:"\2699"}
.iconochive-remove-circle:before{content:"\274e"}
.iconochive-plus-circle:before{content:"\1f5d6"}
.iconochive-minus-circle:before{content:"\1f5d5"}
.iconochive-x:before{content:"\1f5d9"}
.iconochive-fork:before{content:"\22d4"}
.iconochive-trash:before{content:"\1f5d1"}
.iconochive-warning:before{content:"\26a0"}
.iconochive-flash:before{content:"\1f5f2"}
.iconochive-world:before{content:"\1f5fa"}
.iconochive-lock:before{content:"\1f512"}
.iconochive-unlock:before{content:"\1f513"}
.iconochive-twitter:before{content:"\1f426"}
.iconochive-facebook:before{content:"\66"}
.iconochive-googleplus:before{content:"\67"}
.iconochive-reddit:before{content:"\1f47d"}
.iconochive-tumblr:before{content:"\54"}
.iconochive-pinterest:before{content:"\1d4df"}
.iconochive-popcorn:before{content:"\1f4a5"}
.iconochive-email:before{content:"\1f4e7"}
.iconochive-embed:before{content:"\1f517"}
.iconochive-gamepad:before{content:"\1f579"}
.iconochive-Zoom_In:before{content:"\2b"}
.iconochive-Zoom_Out:before{content:"\2d"}
.iconochive-RSS:before{content:"\1f4e8"}
.iconochive-Light_Bulb:before{content:"\1f4a1"}
.iconochive-Add:before{content:"\2295"}
.iconochive-Tab_Activity:before{content:"\2318"}
.iconochive-Forward:before{content:"\23e9"}
.iconochive-Backward:before{content:"\23ea"}
.iconochive-No_Audio:before{content:"\1f508"}
.iconochive-Pause:before{content:"\23f8"}
.iconochive-No_Favorite:before{content:"\2606"}
.iconochive-Unike:before{content:"\2661"}
.iconochive-Song:before{content:"\266b"}
.iconochive-No_Flag:before{content:"\2690"}
.iconochive-Flag:before{content:"\2691"}
.iconochive-Done:before{content:"\2713"}
.iconochive-Check:before{content:"\2714"}
.iconochive-Refresh:before{content:"\27f3"}
.iconochive-Headphones:before{content:"\1f3a7"}
.iconochive-Chart:before{content:"\1f4c8"}
.iconochive-Bookmark:before{content:"\1f4d1"}
.iconochive-Documents:before{content:"\1f4da"}
.iconochive-Newspaper:before{content:"\1f4f0"}
.iconochive-Podcast:before{content:"\1f4f6"}
.iconochive-Radio:before{content:"\1f4fb"}
.iconochive-Cassette:before{content:"\1f4fc"}
.iconochive-Shuffle:before{content:"\1f500"}
.iconochive-Loop:before{content:"\1f501"}
.iconochive-Low_Audio:before{content:"\1f509"}
.iconochive-First:before{content:"\1f396"}
.iconochive-Invisible:before{content:"\1f576"}
.iconochive-Computer:before{content:"\1f5b3"}

70
Docs/Chapter 2.2 Reading a file from CD-ROM_files/style.css

@ -0,0 +1,70 @@
body {
max-width: 900px;
margin: auto;
padding: 8px;
font-family: sans-serif;
font-size: 14px;
//color: white;
//background: black;
}
h {
background-color: #e0e0e0;
padding: 2px;
}
h2 {
border-bottom: 1px solid;
//padding-left: 8px;
}
img {
display: block;
}
.footer-table {
font-size: 14px;
}
.bordered-table {
border-collapse: collapse;
font-size: 11px;
}
.bordered-table th, .bordered-table td {
border: 1px solid;
padding: 4px;
}
hr {
border: none;
border-bottom: 1px solid black;
}
pre {
padding: 8px;
font-size: 12px;
color: black;
background-color: LightGray;
}
/*
FILE ARCHIVED ON 03:35:25 Aug 27, 2022 AND RETRIEVED FROM THE
INTERNET ARCHIVE ON 15:39:09 Sep 05, 2022.
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
*/
/*
playback timings (ms):
captures_list: 107.165
exclusion.robots: 0.073
exclusion.robots.policy: 0.067
cdx.remote: 0.064
esindex: 0.009
LoadShardBlock: 52.713 (3)
PetaboxLoader3.datanode: 140.466 (4)
CDXLines.iter: 14.771 (3)
load_resource: 139.896
PetaboxLoader3.resolve: 47.824
*/

21
Docs/Chapter 2.2 Reading a file from CD-ROM_files/wombat.js
File diff suppressed because it is too large
View File

BIN
Docs/LibPSn00b Reference.pdf

Loading…
Cancel
Save