diff options
-rw-r--r-- | camera.c | 77 | ||||
-rw-r--r-- | doc/libgraphics.ms | 34 | ||||
-rw-r--r-- | doc/libgraphics.pdf | bin | 0 -> 15087 bytes | |||
-rw-r--r-- | doc/libgraphics.ps | 583 | ||||
-rw-r--r-- | doc/mkfile | 15 | ||||
-rw-r--r-- | graphics.h | 42 | ||||
-rw-r--r-- | mkfile | 12 | ||||
-rw-r--r-- | readme | 6 | ||||
-rw-r--r-- | render.c | 135 |
9 files changed, 904 insertions, 0 deletions
diff --git a/camera.c b/camera.c new file mode 100644 index 0000000..ca567c8 --- /dev/null +++ b/camera.c @@ -0,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"); + } +} diff --git a/doc/libgraphics.ms b/doc/libgraphics.ms new file mode 100644 index 0000000..87a23a7 --- /dev/null +++ b/doc/libgraphics.ms @@ -0,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. diff --git a/doc/libgraphics.pdf b/doc/libgraphics.pdf Binary files differnew file mode 100644 index 0000000..0291710 --- /dev/null +++ b/doc/libgraphics.pdf diff --git a/doc/libgraphics.ps b/doc/libgraphics.ps new file mode 100644 index 0000000..1a566f7 --- /dev/null +++ b/doc/libgraphics.ps @@ -0,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 diff --git a/doc/mkfile b/doc/mkfile new file mode 100644 index 0000000..3bac031 --- /dev/null +++ b/doc/mkfile @@ -0,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 diff --git a/graphics.h b/graphics.h new file mode 100644 index 0000000..b9582f3 --- /dev/null +++ b/graphics.h @@ -0,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*); @@ -0,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 @@ -0,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. diff --git a/render.c b/render.c new file mode 100644 index 0000000..d8b7088 --- /dev/null +++ b/render.c @@ -0,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); +} |