ref: 91d8cc8d9adfec7e9b5f415ebd7b7f740cde6e2d
author: rodri <rgl@antares-labs.eu>
date: Fri Apr 17 07:42:47 EDT 2020
standalone version release.
--- /dev/null
+++ b/camera.c
@@ -1,0 +1,77 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <geometry.h>
+#include <graphics.h>
+
+static int
+max(int a, int b)
+{
+ return a > b ? a : b;
+}
+
+static void
+verifycfg(Camera *c)
+{
+ assert(c->viewport != nil);
+ if(c->ptype == Ppersp)
+ assert(c->fov > 0 && c->fov < 360);
+ assert(c->clip.n > 0 && c->clip.n < c->clip.f);
+}
+
+void
+configcamera(Camera *c, Image *v, double fov, double n, double f, Projection p)
+{
+ c->viewport = v;
+ c->fov = fov;
+ c->clip.n = n;
+ c->clip.f = f;
+ c->ptype = p;
+ reloadcamera(c);
+}
+
+void
+placecamera(Camera *c, Point3 p, Point3 focus, Point3 up)
+{
+ c->p = p;
+ if(focus.w == 0)
+ c->bz = focus;
+ else
+ c->bz = normvec3(subpt3(c->p, focus));
+ c->bx = normvec3(crossvec3(up, c->bz));
+ c->by = crossvec3(c->bz, c->bx);
+}
+
+void
+aimcamera(Camera *c, Point3 focus)
+{
+ placecamera(c, c->p, focus, c->by);
+}
+
+void
+reloadcamera(Camera *c)
+{
+ double a;
+ double l, r, b, t;
+
+ verifycfg(c);
+ switch(c->ptype){
+ case Portho:
+ /*
+ r = Dx(c->viewport->r)/2;
+ t = Dy(c->viewport->r)/2;
+ l = -r;
+ b = -t;
+ */
+ l = t = 0;
+ r = Dx(c->viewport->r);
+ b = Dy(c->viewport->r);
+ orthographic(c->proj, l, r, b, t, c->clip.n, c->clip.f);
+ break;
+ case Ppersp:
+ a = (double)Dx(c->viewport->r)/Dy(c->viewport->r);
+ perspective(c->proj, c->fov, a, c->clip.n, c->clip.f);
+ break;
+ default: sysfatal("unknown projection type");
+ }
+}
--- /dev/null
+++ b/doc/libgraphics.ms
@@ -1,0 +1,34 @@
+.TL
+libgraphics
+.AU
+Rodrigo G. López
+.sp
+rgl@antares-labs.eu
+.AI
+Antares Telecom Laboratories
+Albatera, Alicante
+.FS
+ACHTUNG! this is a
+.B "WORK IN PROGRESS"
+.FE
+.NH 1
+Data Structures
+.NH 2
+Camera
+.P1
+struct Camera {
+ RFrame3; /* VCS */
+ Image *viewport;
+ double fov; /* vertical FOV */
+ struct {
+ double n, f; /* near and far clipping planes */
+ } clip;
+ Projection ptype;
+ Matrix3 proj; /* VCS to viewport xform */
+};
+.P2
+.PP
+A camera is an image capturing entity, analog to the real world device
+we all know, that allows us to see the virtual 3-D world by projecting
+it into a viewport we can attach to a screen or window for real-time
+visualization or write out into a file.
--- /dev/null
+++ b/doc/libgraphics.pdf
@@ -1,0 +1,295 @@
+%PDF-1.2
+%�쏢
+5 0 obj
+<</Length 6 0 R/Filter /FlateDecode>>
+stream
+x�e��n�0��z
+�Ty�4K�/vi��� i=C�8n���[۹��S�FIIP�B��O$�!�u�eKB���#/D�8�����|.2�� d���$ A��6�fכ�}]����p�Y�#`2�%���}��`�a����cY�s�@��~�\�ߣ髁5f3��p�ɓOJ,����ς����ZX�Mכ����"s������|�IS�xM���I-Re݉s?P��D�2��������?�"Q� ���<�ѩi��r+�B�녃s,)����pz��j��Kp��q�C
+��8�ҧ��Đ�� �"�}�����(n�������[�?La%Q��q_�S��(Sz�+��i����������ߗ6&��X͋�z�rf����礞�endstream
+endobj
+6 0 obj
+386
+endobj
+4 0 obj
+<</Type/Page/MediaBox [0 0 612 792]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF /Text]
+/Font 17 0 R
+>>
+/Contents 5 0 R
+>>
+endobj
+3 0 obj
+<< /Type /Pages /Kids [
+4 0 R
+] /Count 1
+>>
+endobj
+1 0 obj
+<</Type /Catalog /Pages 3 0 R
+>>
+endobj
+17 0 obj
+<</R15
+15 0 R/R8
+8 0 R/R10
+10 0 R/R12
+12 0 R/R14
+14 0 R/R16
+16 0 R>>
+endobj
+15 0 obj
+<</BaseFont/Times-Roman/Type/Font
+/Subtype/Type1>>
+endobj
+8 0 obj
+<</BaseFont/DIDNIM+LucidaSans-Demi/FontDescriptor 7 0 R/Type/Font
+/FirstChar 32/LastChar 117/Widths[
+319 0 0 0 0 0 0 0 0 0 0 0 0 0 247 0
+0 639 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 712 793 601 0 746 0 331 0 710 0 0 768 823
+613 0 690 571 0 0 0 904 0 0 0 0 0 0 0 0
+0 588 663 532 0 586 0 660 657 325 0 0 325 970 0 0
+663 0 454 566 405 657]
+/Encoding/WinAnsiEncoding/Subtype/Type1>>
+endobj
+10 0 obj
+<</BaseFont/ARKRES+LucidaSans-Italic/FontDescriptor 9 0 R/Type/Font
+/FirstChar 32/LastChar 243/Widths[
+316 0 0 0 0 0 0 0 0 0 0 0 0 633 316 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+858 0 0 0 0 0 0 702 0 0 0 0 545 0 0 0
+0 0 632 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 608 608 0 608 529 0 608 0 289 0 0 289 0 621 566
+608 0 478 489 383 621 0 0 0 0 536 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 566]
+/Encoding 22 0 R/Subtype/Type1>>
+endobj
+22 0 obj
+<</Type/Encoding/BaseEncoding/WinAnsiEncoding/Differences[
+45/minus]>>
+endobj
+12 0 obj
+<</BaseFont/XXIYSF+LucidaSansUnicode00/FontDescriptor 11 0 R/Type/Font
+/FirstChar 32/LastChar 116/Widths[
+316 316 0 0 0 0 0 0 0 0 0 0 316 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 690 0 692 0 0 0 723 735 0 0 0 533 0 739 0
+0 0 0 0 632 693 0 0 0 0 0 0 0 0 0 0
+0 552 630 512 0 557 0 0 620 289 0 0 289 934 620 614
+0 0 409 509 374]
+/Encoding 23 0 R/Subtype/Type1>>
+endobj
+23 0 obj
+<</Type/Encoding/BaseEncoding/WinAnsiEncoding/Differences[
+32/0020/0021
+44/002c
+65/0041
+67/0043
+71/0047/0048
+76/004c
+78/004e
+84/0054/0055
+97/0061/0062/0063
+101/0065
+104/0068/0069
+108/006c/006d/006e/006f
+114/0072/0073/0074]>>
+endobj
+14 0 obj
+<</BaseFont/SBRUOU+LucidaTypewriter/FontDescriptor 13 0 R/Type/Font
+/FirstChar 59/LastChar 125/Widths[ 723 0 0 0 0
+0 0 0 723 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 723 0 723 0 723 0 0 0 0 0 0 0 723 0 0
+0 0 723 723 723 723 0 0 0 0 0 723 0 723]
+/Encoding/WinAnsiEncoding/Subtype/Type1>>
+endobj
+16 0 obj
+<</BaseFont/Symbol/Type/Font
+/Subtype/Type1>>
+endobj
+7 0 obj
+<</Type/FontDescriptor/FontName/DIDNIM+LucidaSans-Demi/FontBBox[0 -205 895 771]/Flags 4
+/Ascent 771
+/CapHeight 771
+/Descent -205
+/ItalicAngle 0
+/StemV 134
+/MissingWidth 319
+/CharSet(/c/N/C/p/e/O/D/P/E/r/g/s/h/R/G/t/i/S/u/I/l/a/K/m/b/W/space/period/one)/FontFile3 18 0 R>>
+endobj
+18 0 obj
+<</Filter/LZWDecode
+/Subtype/Type1C/Length 2925>>stream
++T�u��g2���S ��"!V.b�2��|D+��!^]��Y�E��dFX�w-`���caI��+���{����{���E�c��:���N}��XE���>;� �@�{+�WIJ�Aq^FR� �s�p^3C��¨�^D��a�ATpP�B+(���"]j�B`X�x7Fa�G�pS�v7B5@!G��|�-�C@�=���aT��<G�،�iI��Hk/nl�h3�+pR����lN��;%@@���a��n ����HD�U�!�@++�xA�+� P3��E��\P �D'�@��xE��%C��v�E�:���z�
+�Nm!pq���藞j@#F�L�Cĭ}�jW��=�8�c+!p�Ю�~#�����3����0{���Ǹ�T��}���!C�����E������Y<4�X�\+ ($�H[��6H�
+�|9)�2�X�#8M�q'D���I+��Z���J�,"Ĩ��U��b.y�xJ.�'D"+�������o�rJ�nq�p7�.7���Y�|؊L��\��X �Ja\
+�6'�`� �A
+!+@>@+�� ���p�X <!"A"a&"+`"�Pa�K���Rf&��Ld���W�˸���S >����(b*�)���aRĮ> ��bH���+�*`�����@� �����b)�`+m��+M�A�$+endstream
+endobj
+9 0 obj
+<</Type/FontDescriptor/FontName/ARKRES+LucidaSans-Italic/FontBBox[0 -205 889 771]/Flags 4
+/Ascent 771
+/CapHeight 771
+/Descent -205
+/ItalicAngle 0
+/StemV 133
+/MissingWidth 316
+/CharSet(/L/n/minus/z/o/d/at/p/e/r/g/oacute/s/R/G/t/i/u/acute/l/a/b/space/period)/FontFile3 19 0 R>>
+endobj
+19 0 obj
+<</Filter/LZWDecode
+/Subtype/Type1C/Length 2572>>stream
++�� +�&�
+~+E��@�[�f!�y�G�Do�����}�a�p-̣��O��yRs�>O%)LU�aZK�\�S�� +� 4D��Y�E�ɠq�(gHi����a�����&lR��1G��>R���+{�٬���t�d��d�91b��.a#�cAnDf�"+��b�N
+�B*0�_�zx` �}��+G�FaX}�u��H���d��(#����P��q�����\R��f&���BtK�qL%�eB�9���B�[`|/�P�!A��o�դ�r;�SIY,%���Ǹ_#+�\-��#���bL=`02Cp��,E�2����X
+�z'+C(Z�1<-�B�S
+�B*D��B\S+�%� ���J�X,EP��B�A��j� �M��0��z!�G�aDhua*:���Èp��E���i��4U�<�]�3 @���@a !�*�`�%+
+,D ���D������;��0X���,{���#�� Cܡ���=�j]B�j�q;�X�´9
+@�*C0�I�}��r��+��$�h�������BdP�P<$�p��lHE0'K����{��n=���K�H �d>��7��+�(6+!+a�A�!�^��A�@v`���*A(�*�,���J��+endstream
+endobj
+11 0 obj
+<</Type/FontDescriptor/FontName/XXIYSF+LucidaSansUnicode00/FontBBox[0 -157 843 771]/Flags 4
+/Ascent 771
+/CapHeight 771
+/Descent -157
+/ItalicAngle 0
+/StemV 126
+/MissingWidth 316
+/CharSet(/006e/0063/002c/006f/004e/0043/0065/0020/0021/0072/0073/0068/0047/0074/0069/0048/0054/0055/006c/0061/006d/0062/004c/0041)/FontFile3 20 0 R>>
+endobj
+20 0 obj
+<</Filter/LZWDecode
+/Subtype/Type1C/Length 2389>>stream
++�3I��S0��eSq��o2F4L� �_��:E��/���.� � 5hBOw�E����+4+DI+ +]��+��!�hҜ�hgY�P�4{�GX{�GX*�gX���*i�Ĺ+���J�a(i. &��O�R�. �i�x����^��AM�d�O��A���iE��X�E���"+ap�X���c��:#�4"��5
+c0�K���<B� >�@@d�C�~@�X{����tC�r3���M ���M+����H�"@��tG�.v�XS��2P��QJY�el�E�$0>c�@�b�}�:VL3�&��/硰+����C��D$XrE�� v*c��E��Y�T����Yf>i�f `&��I��19L�@8�M���H�$��F�8��9�`��d!��q��%��@�j�g�Pg�e�$j���L���+�{����H��C����p�\T")X��J�A���,C���"���bfm��,"�r���BHQ� �8s��V��8DX[l"-�
+"D���1�X�B�E��)���l=��"�8 PF1C�X�f8�@�"°�0'1t/D���LG�A&%��+���l!�C��+@�+ah�t
+���>+���V�x���=�8|��va���*���}+!�9�� h� �6;`f
+G�u ��T�Q|0+�X9a7DX�$T %x����`���=���\V_�C�GQ%]K�L1����xǠ�}��乥���HKҷ�%�~�\���D m��$>@rRXP�����4�����^�Q.DX�"d1 @�#C����<��:���.���Qp����.+endstream
+endobj
+13 0 obj
+<</Type/FontDescriptor/FontName/SBRUOU+LucidaTypewriter/FontBBox[0 -157 720 771]/Flags 5
+/Ascent 771
+/CapHeight 771
+/Descent -157
+/ItalicAngle 0
+/StemV 108
+/AvgWidth 723
+/MaxWidth 723
+/MissingWidth 723
+/CharSet(/c/C/e/r/s/t/u/semicolon/braceleft/a/m/braceright)/FontFile3 21 0 R>>
+endobj
+21 0 obj
+<</Filter/LZWDecode
+/Subtype/Type1C/Length 1920>>stream
++�+DF��{���tA�(>H$�J��C�3�&i��ƙ�|O��qH*d� +�� 5�!"0��L�a��( "h�6��>B�������~]$�ję4H���l�à�A����=�D �!a�����,���&{��1ZC�8>P�ĹS������|!����{��s�}�X*T��Y�<��r/B�Ba�%b��+
+�`�E���v{��!�*&�.M� �$G��2H��,��
+,CY6��La��?��Hf����+��N$�������J#y�>����&y�ke�� W[����
+O�'�uħ�,��:f�d���g�2>��I��}�`"�`���;�p�/���b�E��00E��LG��3�8`�CAX�",3���%�؟�tD �2��!%����LJ`�㭛��(! ��"À� Bd>��f!E0�,\u���X�T���,`�"�>��6�X�Ck6 � Q0�C�5����k{�� ���!Hd�qx;�vb�Q0@(� cq�� �Q�F�F`�+�r&0�#hZ����b�,�a��@� ��i�@�"�x�eW+ ��bCT3� �"2 |�!x<��ma=�A C;�e`��j9Q(�<
+���"�苮!�J�@�tB+�>+& �����4++endstream
+endobj
+2 0 obj
+<</Producer(AFPL Ghostscript 8.53)
+/CreationDate(D:20191105235851)
+/ModDate(D:20191105235851)>>endobj
+xref
+0 24
+0000000000 65535 f
+0000000691 00000 n
+0000014343 00000 n
+0000000632 00000 n
+0000000490 00000 n
+0000000015 00000 n
+0000000471 00000 n
+0000002987 00000 n
+0000000891 00000 n
+0000006282 00000 n
+0000001280 00000 n
+0000009228 00000 n
+0000001990 00000 n
+0000012043 00000 n
+0000002605 00000 n
+0000000824 00000 n
+0000002925 00000 n
+0000000739 00000 n
+0000003274 00000 n
+0000006573 00000 n
+0000009571 00000 n
+0000012340 00000 n
+0000001903 00000 n
+0000002364 00000 n
+trailer
+<< /Size 24 /Root 1 0 R /Info 2 0 R
+/ID [<83B4B497B4BE760E2302DD9469D51E12><83B4B497B4BE760E2302DD9469D51E12>]
+>>
+startxref
+14453
+%%EOF
--- /dev/null
+++ b/doc/libgraphics.ps
@@ -1,0 +1,583 @@
+%!PS-Adobe-2.0
+%%Version: 0.1
+%%Creator: troff, Plan 9 edition
+%%DocumentFonts: (atend)
+%%Pages: (atend)
+%%EndComments
+%
+% Version 3.3.2 prologue for troff files.
+%
+
+/#copies 1 store
+/aspectratio 1 def
+/formsperpage 1 def
+/landscape false def
+/linewidth .3 def
+/magnification 1 def
+/margin 0 def
+/orientation 0 def
+/resolution 720 def
+/rotation 1 def
+/xoffset 0 def
+/yoffset 0 def
+
+/roundpage true def
+/useclippath true def
+/pagebbox [0 0 612 792] def
+
+/R /Times-Roman def
+/I /Times-Italic def
+/B /Times-Bold def
+/BI /Times-BoldItalic def
+/H /Helvetica def
+/HI /Helvetica-Oblique def
+/HB /Helvetica-Bold def
+/HX /Helvetica-BoldOblique def
+/CW /Courier def
+/CO /Courier def
+/CI /Courier-Oblique def
+/CB /Courier-Bold def
+/CX /Courier-BoldOblique def
+/PA /Palatino-Roman def
+/PI /Palatino-Italic def
+/PB /Palatino-Bold def
+/PX /Palatino-BoldItalic def
+/Hr /Helvetica-Narrow def
+/Hi /Helvetica-Narrow-Oblique def
+/Hb /Helvetica-Narrow-Bold def
+/Hx /Helvetica-Narrow-BoldOblique def
+/KR /Bookman-Light def
+/KI /Bookman-LightItalic def
+/KB /Bookman-Demi def
+/KX /Bookman-DemiItalic def
+/AR /AvantGarde-Book def
+/AI /AvantGarde-BookOblique def
+/AB /AvantGarde-Demi def
+/AX /AvantGarde-DemiOblique def
+/NR /NewCenturySchlbk-Roman def
+/NI /NewCenturySchlbk-Italic def
+/NB /NewCenturySchlbk-Bold def
+/NX /NewCenturySchlbk-BoldItalic def
+/ZD /ZapfDingbats def
+/ZI /ZapfChancery-MediumItalic def
+/S /S def
+/S1 /S1 def
+/GR /Symbol def
+
+/inch {72 mul} bind def
+/min {2 copy gt {exch} if pop} bind def
+
+/setup {
+ counttomark 2 idiv {def} repeat pop
+
+ landscape {/orientation 90 orientation add def} if
+ /scaling 72 resolution div def
+ linewidth setlinewidth
+ 1 setlinecap
+
+ pagedimensions
+ xcenter ycenter translate
+ orientation rotation mul rotate
+ width 2 div neg height 2 div translate
+ xoffset inch yoffset inch neg translate
+ margin 2 div dup neg translate
+ magnification dup aspectratio mul scale
+ scaling scaling scale
+
+ addmetrics
+ 0 0 moveto
+} def
+
+/pagedimensions {
+ useclippath userdict /gotpagebbox known not and {
+ /pagebbox [clippath pathbbox newpath] def
+ roundpage currentdict /roundpagebbox known and {roundpagebbox} if
+ } if
+ pagebbox aload pop
+ 4 -1 roll exch 4 1 roll 4 copy
+ landscape {4 2 roll} if
+ sub /width exch def
+ sub /height exch def
+ add 2 div /xcenter exch def
+ add 2 div /ycenter exch def
+ userdict /gotpagebbox true put
+} def
+
+/addmetrics {
+ /Symbol /S null Sdefs cf
+ /Times-Roman /S1 StandardEncoding dup length array copy S1defs cf
+} def
+
+/pagesetup {
+ /page exch def
+ currentdict /pagedict known currentdict page known and {
+ page load pagedict exch get cvx exec
+ } if
+} def
+
+/decodingdefs [
+ {counttomark 2 idiv {y moveto show} repeat}
+ {neg /y exch def counttomark 2 idiv {y moveto show} repeat}
+ {neg moveto {2 index stringwidth pop sub exch div 0 32 4 -1 roll widthshow} repeat}
+ {neg moveto {spacewidth sub 0.0 32 4 -1 roll widthshow} repeat}
+ {counttomark 2 idiv {y moveto show} repeat}
+ {neg setfunnytext}
+] def
+
+/setdecoding {/t decodingdefs 3 -1 roll get bind def} bind def
+
+/w {neg moveto show} bind def
+/m {neg dup /y exch def moveto} bind def
+/done {/lastpage where {pop lastpage} if} def
+
+/f {
+ dup /font exch def findfont exch
+ dup /ptsize exch def scaling div dup /size exch def scalefont setfont
+ linewidth ptsize mul scaling 10 mul div setlinewidth
+ /spacewidth ( ) stringwidth pop def
+} bind def
+
+/changefont {
+ /fontheight exch def
+ /fontslant exch def
+ currentfont [
+ 1 0
+ fontheight ptsize div fontslant sin mul fontslant cos div
+ fontheight ptsize div
+ 0 0
+ ] makefont setfont
+} bind def
+
+/sf {f} bind def
+
+/cf {
+ dup length 2 idiv
+ /entries exch def
+ /chtab exch def
+ /newencoding exch def
+ /newfont exch def
+
+ findfont dup length 1 add dict
+ /newdict exch def
+ {1 index /FID ne {newdict 3 1 roll put}{pop pop} ifelse} forall
+
+ newencoding type /arraytype eq {newdict /Encoding newencoding put} if
+
+ newdict /Metrics entries dict put
+ newdict /Metrics get
+ begin
+ chtab aload pop
+ 1 1 entries {pop def} for
+ newfont newdict definefont pop
+ end
+} bind def
+
+%
+% A few arrays used to adjust reference points and character widths in some
+% of the printer resident fonts. If square roots are too high try changing
+% the lines describing /radical and /radicalex to,
+%
+% /radical [0 -75 550 0]
+% /radicalex [-50 -75 500 0]
+%
+% Move braceleftbt a bit - default PostScript character is off a bit.
+%
+
+/Sdefs [
+ /bracketlefttp [201 500]
+ /bracketleftbt [201 500]
+ /bracketrighttp [-81 380]
+ /bracketrightbt [-83 380]
+ /braceleftbt [203 490]
+ /bracketrightex [220 -125 500 0]
+ /radical [0 0 550 0]
+ /radicalex [-50 0 500 0]
+ /parenleftex [-20 -170 0 0]
+ /integral [100 -50 500 0]
+ /infinity [10 -75 730 0]
+] def
+
+/S1defs [
+ /underscore [0 80 500 0]
+ /endash [7 90 650 0]
+] def
+%
+% Tries to round clipping path dimensions, as stored in array pagebbox, so they
+% match one of the known sizes in the papersizes array. Lower left coordinates
+% are always set to 0.
+%
+
+/roundpagebbox {
+ 7 dict begin
+ /papersizes [8.5 inch 11 inch 14 inch 17 inch] def
+
+ /mappapersize {
+ /val exch def
+ /slop .5 inch def
+ /diff slop def
+ /j 0 def
+ 0 1 papersizes length 1 sub {
+ /i exch def
+ papersizes i get val sub abs
+ dup diff le {/diff exch def /j i def} {pop} ifelse
+ } for
+ diff slop lt {papersizes j get} {val} ifelse
+ } def
+
+ pagebbox 0 0 put
+ pagebbox 1 0 put
+ pagebbox dup 2 get mappapersize 2 exch put
+ pagebbox dup 3 get mappapersize 3 exch put
+ end
+} bind def
+
+%%EndProlog
+%%BeginSetup
+mark
+%
+% Encoding vector and redefinition of findfont for the ISO Latin1 standard.
+% The 18 characters missing from ROM based fonts on older printers are noted
+% below.
+%
+
+/ISOLatin1Encoding [
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /space
+ /exclam
+ /quotedbl
+ /numbersign
+ /dollar
+ /percent
+ /ampersand
+ /quoteright
+ /parenleft
+ /parenright
+ /asterisk
+ /plus
+ /comma
+ /minus
+ /period
+ /slash
+ /zero
+ /one
+ /two
+ /three
+ /four
+ /five
+ /six
+ /seven
+ /eight
+ /nine
+ /colon
+ /semicolon
+ /less
+ /equal
+ /greater
+ /question
+ /at
+ /A
+ /B
+ /C
+ /D
+ /E
+ /F
+ /G
+ /H
+ /I
+ /J
+ /K
+ /L
+ /M
+ /N
+ /O
+ /P
+ /Q
+ /R
+ /S
+ /T
+ /U
+ /V
+ /W
+ /X
+ /Y
+ /Z
+ /bracketleft
+ /backslash
+ /bracketright
+ /asciicircum
+ /underscore
+ /quoteleft
+ /a
+ /b
+ /c
+ /d
+ /e
+ /f
+ /g
+ /h
+ /i
+ /j
+ /k
+ /l
+ /m
+ /n
+ /o
+ /p
+ /q
+ /r
+ /s
+ /t
+ /u
+ /v
+ /w
+ /x
+ /y
+ /z
+ /braceleft
+ /bar
+ /braceright
+ /asciitilde
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /dotlessi
+ /grave
+ /acute
+ /circumflex
+ /tilde
+ /macron
+ /breve
+ /dotaccent
+ /dieresis
+ /.notdef
+ /ring
+ /cedilla
+ /.notdef
+ /hungarumlaut
+ /ogonek
+ /caron
+ /space
+ /exclamdown
+ /cent
+ /sterling
+ /currency
+ /yen
+ /brokenbar % missing
+ /section
+ /dieresis
+ /copyright
+ /ordfeminine
+ /guillemotleft
+ /logicalnot
+ /hyphen
+ /registered
+ /macron
+ /degree % missing
+ /plusminus % missing
+ /twosuperior % missing
+ /threesuperior % missing
+ /acute
+ /mu % missing
+ /paragraph
+ /periodcentered
+ /cedilla
+ /onesuperior % missing
+ /ordmasculine
+ /guillemotright
+ /onequarter % missing
+ /onehalf % missing
+ /threequarters % missing
+ /questiondown
+ /Agrave
+ /Aacute
+ /Acircumflex
+ /Atilde
+ /Adieresis
+ /Aring
+ /AE
+ /Ccedilla
+ /Egrave
+ /Eacute
+ /Ecircumflex
+ /Edieresis
+ /Igrave
+ /Iacute
+ /Icircumflex
+ /Idieresis
+ /Eth % missing
+ /Ntilde
+ /Ograve
+ /Oacute
+ /Ocircumflex
+ /Otilde
+ /Odieresis
+ /multiply % missing
+ /Oslash
+ /Ugrave
+ /Uacute
+ /Ucircumflex
+ /Udieresis
+ /Yacute % missing
+ /Thorn % missing
+ /germandbls
+ /agrave
+ /aacute
+ /acircumflex
+ /atilde
+ /adieresis
+ /aring
+ /ae
+ /ccedilla
+ /egrave
+ /eacute
+ /ecircumflex
+ /edieresis
+ /igrave
+ /iacute
+ /icircumflex
+ /idieresis
+ /eth % missing
+ /ntilde
+ /ograve
+ /oacute
+ /ocircumflex
+ /otilde
+ /odieresis
+ /divide % missing
+ /oslash
+ /ugrave
+ /uacute
+ /ucircumflex
+ /udieresis
+ /yacute % missing
+ /thorn % missing
+ /ydieresis
+] def
+
+/NewFontDirectory FontDirectory maxlength dict def
+
+%
+% Apparently no guarantee findfont is defined in systemdict so the obvious
+%
+% systemdict /findfont get exec
+%
+% can generate an error. So far the only exception is a VT600 (version 48.0).
+%
+
+userdict /@RealFindfont known not {
+ userdict begin
+ /@RealFindfont systemdict begin /findfont load end def
+ end
+} if
+
+/findfont {
+ dup NewFontDirectory exch known not {
+ dup
+ %dup systemdict /findfont get exec % not always in systemdict
+ dup userdict /@RealFindfont get exec
+ dup /Encoding get StandardEncoding eq {
+ dup length dict begin
+ {1 index /FID ne {def}{pop pop} ifelse} forall
+ /Encoding ISOLatin1Encoding def
+ currentdict
+ end
+ /DummyFontName exch definefont
+ } if
+ NewFontDirectory 3 1 roll put
+ } if
+ NewFontDirectory exch get
+} bind def
+
+%%Patch from lp
+%%EndPatch from lp
+
+setup
+%%EndSetup
+%%Page: 1 1
+/saveobj save def
+mark
+1 pagesetup
+12 /LucidaSans-Demi f
+(libgraphics) 2533 1220 w
+10 /LucidaSans-Italic f
+(Rodrigo G. L\363pez) 2469 1480 w
+(rgl@antares-labs.eu) 2377 1760 w
+10 /LucidaSansUnicode00 f
+(Antares Telecom Laboratories) 2156 1960 w
+(Albatera, Alicante) 2451 2100 w
+10 /LucidaSans-Demi f
+(1.) 720 2700 w
+(Data Structures) 873 2700 w
+(1.1.) 720 2940 w
+(Camera) 962 2940 w
+9 /LucidaTypewriter f
+(struct) 920 3110 w
+(Camera) 1375 3110 w
+({) 1830 3110 w
+(};) 920 3330 w
+10 /LucidaSansUnicode00 f
+(A camera) 970 3546 w
+8 /S1 f
+(__________________) 720 6980 w
+8 /LucidaSansUnicode00 f
+(ACHTUNG!) 720 7080 w
+(this) 1163 7080 w
+(is) 1333 7080 w
+(a) 1423 7080 w
+8 /LucidaSans-Demi f
+(WORK) 1493 7080 w
+(IN) 1769 7080 w
+(PROGRESS) 1883 7080 w
+cleartomark
+showpage
+saveobj restore
+%%EndPage: 1 1
+%%Trailer
+done
+%%DocumentFonts: S1 LucidaSansUnicode00 LucidaSans-Demi LucidaSans-Italic LucidaTypewriter
+%%Pages: 1
--- /dev/null
+++ b/doc/mkfile
@@ -1,0 +1,15 @@
+FONTS='.FP lucidasans'
+DOCNAME=libgraphics
+
+all:VQ: $DOCNAME.ps $DOCNAME.pdf
+
+clean:VQ:
+ rm -f $DOCNAME.ps $DOCNAME.pdf
+
+$DOCNAME.ps:V: $DOCNAME.ms
+ {echo $FONTS; cat $prereq}> _$prereq
+ eval `{doctype _$prereq} | lp -dstdout > $target && rm -f _$prereq
+
+$DOCNAME.pdf:V: $DOCNAME.ps
+ cat /sys/doc/docfonts $prereq > _$prereq
+ ps2pdf _$prereq $target && rm -f _$prereq
--- /dev/null
+++ b/graphics.h
@@ -1,0 +1,42 @@
+typedef enum {
+ Portho, /* orthographic */
+ Ppersp /* perspective */
+} Projection;
+
+typedef struct Vertex Vertex;
+typedef struct Camera Camera;
+
+struct Vertex {
+ Point3 p; /* position */
+ Point3 n; /* surface normal */
+};
+
+struct Camera {
+ RFrame3; /* VCS */
+ Image *viewport;
+ double fov; /* vertical FOV */
+ struct {
+ double n, f;
+ } clip;
+ Matrix3 proj; /* VCS to NDC xform */
+ Projection ptype;
+};
+
+/* Camera */
+void configcamera(Camera*, Image*, double, double, double, Projection);
+void placecamera(Camera*, Point3, Point3, Point3);
+void aimcamera(Camera*, Point3);
+void reloadcamera(Camera*);
+
+/* rendering */
+#define FPS2MS(n) (1000/(n))
+#define WORLD2VCS(cp, p) (rframexform3((p), *(cp)))
+#define VCS2NDC(cp, p) (xform3((p), (cp)->proj))
+#define WORLD2NDC(cp, p) (VCS2NDC((cp), WORLD2VCS((cp), (p))))
+int isclipping(Point3);
+Point toviewport(Camera*, Point3);
+Point2 fromviewport(Camera*, Point);
+void perspective(Matrix3, double, double, double, double);
+void orthographic(Matrix3, double, double, double, double, double, double);
+void line3(Camera*, Point3, Point3, int, int, Image*);
+Point string3(Camera*, Point3, Image*, Font*, char*);
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,12 @@
+</$objtype/mkfile
+
+LIB=libgraphics.a$O
+OFILES=\
+ camera.$O\
+ render.$O\
+
+HFILES=graphics.h ../libgeometry/geometry.h
+
+CFLAGS=$CFLAGS -I. -I../libgeometry
+
+</sys/src/cmd/mklib
--- /dev/null
+++ b/readme
@@ -1,0 +1,6 @@
+libgraphics
+
+Libgraphics provides 3D computer graphics through draw(3).
+
+Still in early stages of research, subject to change, drastically, at
+any given time.
--- /dev/null
+++ b/render.c
@@ -1,0 +1,135 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <geometry.h>
+#include <graphics.h>
+
+//static Memimage*
+//imagetomemimage(Image *src)
+//{
+// Memimage *dst;
+// uchar *buf;
+// uint buflen;
+//
+// buflen = Dx(src->r)*Dy(src->r);
+// buflen *= (chantodepth(src->chan)+7)/8;
+// buf = malloc(buflen);
+// if(buf == nil)
+// sysfatal("malloc: %r");
+// dst = allocmemimage(src->r, src->chan);
+// if(dst == nil)
+// sysfatal("allocmemimage: %r");
+// if(src->repl){
+// dst->flags |= Frepl;
+// dst->clipr = Rect(-1e6, -1e6, 1e6, 1e6);
+// }
+// unloadimage(src, src->r, buf, buflen);
+// loadmemimage(dst, src->r, buf, buflen);
+// free(buf);
+// return dst;
+//}
+
+static Point2
+flatten(Camera *c, Point3 p)
+{
+ Point2 p2;
+ Matrix S = {
+ Dx(c->viewport->r)/2, 0, 0,
+ 0, Dy(c->viewport->r)/2, 0,
+ 0, 0, 1,
+ }, T = {
+ 1, 0, 1,
+ 0, 1, 1,
+ 0, 0, 1,
+ };
+
+ p2 = Pt2(p.x, p.y, p.w);
+ if(p2.w != 0)
+ p2 = divpt2(p2, p2.w);
+ mulm(S, T);
+ p2 = xform(p2, S);
+ return p2;
+}
+
+/* requires p to be in NDC */
+int
+isclipping(Point3 p)
+{
+ if(p.x > p.w || p.x < -p.w ||
+ p.y > p.w || p.y < -p.w ||
+ p.z > p.w || p.z < 0)
+ return 1;
+ return 0;
+}
+
+Point
+toviewport(Camera *c, Point3 p)
+{
+ Point2 p2;
+ RFrame rf = {
+ c->viewport->r.min.x, c->viewport->r.max.y, 1,
+ 1, 0, 0,
+ 0, -1, 0
+ };
+
+ p2 = invrframexform(flatten(c, p), rf);
+ return Pt(p2.x, p2.y);
+}
+
+Point2
+fromviewport(Camera *c, Point p)
+{
+ RFrame rf = {
+ c->viewport->r.min.x, c->viewport->r.max.y, 1,
+ 1, 0, 0,
+ 0, -1, 0
+ };
+
+ return rframexform(Pt2(p.x,p.y,1), rf);
+}
+
+void
+perspective(Matrix3 m, double fov, double a, double n, double f)
+{
+ double cotan;
+
+ cotan = 1/tan(fov/2*DEG);
+ identity3(m);
+ m[0][0] = cotan/a;
+ m[1][1] = cotan;
+ m[2][2] = -(f+n)/(f-n);
+ m[2][3] = -2*f*n/(f-n);
+ m[3][2] = -1;
+}
+
+void
+orthographic(Matrix3 m, double l, double r, double b, double t, double n, double f)
+{
+ identity3(m);
+ m[0][0] = 2/(r - l);
+ m[1][1] = 2/(t - b);
+ m[2][2] = -2/(f - n);
+ m[0][3] = -(r + l)/(r - l);
+ m[1][3] = -(t + b)/(t - b);
+ m[2][3] = -(f + n)/(f - n);
+}
+
+void
+line3(Camera *c, Point3 p0, Point3 p1, int end0, int end1, Image *src)
+{
+ p0 = WORLD2NDC(c, p0);
+ p1 = WORLD2NDC(c, p1);
+ if(isclipping(p0) || isclipping(p1))
+ return;
+ line(c->viewport, toviewport(c, p0), toviewport(c, p1), end0, end1, 0, src, ZP);
+}
+
+Point
+string3(Camera *c, Point3 p, Image *src, Font *f, char *s)
+{
+ p = WORLD2NDC(c, p);
+ if(isclipping(p))
+ return Pt(-1,-1);
+ return string(c->viewport, toviewport(c, p), src, ZP, f, s);
+}