summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--camera.c2
-rw-r--r--color.c40
-rw-r--r--fb.c102
-rw-r--r--graphics.h15
-rw-r--r--render.c26
-rw-r--r--texture.c7
-rw-r--r--util.c42
7 files changed, 181 insertions, 53 deletions
diff --git a/camera.c b/camera.c
index bd6ccb5..2f7daf7 100644
--- a/camera.c
+++ b/camera.c
@@ -241,7 +241,7 @@ shootcamera(Camera *c, Shadertab *s)
job->shaders = s;
job->donec = chancreate(sizeof(void*), 0);
- fbctl->reset(fbctl, c->clearcolor);
+ fbctl->reset(fbctl);
t0 = nanosec();
sendp(c->rctl->jobq, job);
recvp(job->donec);
diff --git a/color.c b/color.c
index fdbd0a0..6a6023d 100644
--- a/color.c
+++ b/color.c
@@ -8,6 +8,39 @@
#include "graphics.h"
#include "internal.h"
+ulong
+col2ul(Color c)
+{
+ uchar cbuf[4];
+
+ cbuf[0] = fclamp(c.a, 0, 1)*0xFF;
+ cbuf[1] = fclamp(c.b, 0, 1)*0xFF;
+ cbuf[2] = fclamp(c.g, 0, 1)*0xFF;
+ cbuf[3] = fclamp(c.r, 0, 1)*0xFF;
+ return cbuf[3]<<24 | cbuf[2]<<16 | cbuf[1]<<8 | cbuf[0];
+}
+
+Color
+ul2col(ulong l)
+{
+ Color c;
+
+ c.a = (l & 0xff)/255.0;
+ c.b = (l>>8 & 0xff)/255.0;
+ c.g = (l>>16 & 0xff)/255.0;
+ c.r = (l>>24 & 0xff)/255.0;
+ return c;
+}
+
+int
+hasalpha(ulong chan)
+{
+ for(; chan; chan >>= 8)
+ if(TYPE(chan) == CAlpha)
+ return 1;
+ return 0;
+}
+
/*
* see also “The Importance of Being Linear”, Gritz and d'Eon, GPU Gems 3, Ch. 24, December 2007
*/
@@ -141,13 +174,6 @@ linear2srgb(Color c)
return c;
}
-ulong
-rgba2xrgb(ulong c)
-{
- return (c & 0xFF)<<24|(c>>24 & 0xFF)<<16|
- (c>>16 & 0xFF)<<8|(c>>8 & 0xFF);
-}
-
/* tone mapping */
diff --git a/fb.c b/fb.c
index ec1c056..7a11571 100644
--- a/fb.c
+++ b/fb.c
@@ -95,6 +95,23 @@ rasterconvF2C(Raster *dst, Raster *src)
}
static void
+premulalpha(Raster *r)
+{
+ Color c;
+ ulong *p, len;
+
+ len = Dx(r->r)*Dy(r->r);
+ p = r->data;
+ while(len--){
+ c = ul2col(*p);
+ c.r *= c.a;
+ c.g *= c.a;
+ c.b *= c.a;
+ *p++ = col2ul(c);
+ }
+}
+
+static void
fb_createraster(Framebuf *fb, char *name, ulong chan)
{
Raster *r;
@@ -135,11 +152,15 @@ upscaledraw(Raster *fb, Image *dst, Point off, Point scale, uint filter)
void (*filterfn)(ulong*, Raster*, Point);
Rectangle blkr;
Point sp, dp;
+ Image *tmp;
ulong *blk;
filterfn = nil;
blk = emalloc(scale.x*scale.y*4);
blkr = Rect(0,0,scale.x,scale.y);
+ tmp = allocimage(display, dst->r, RGBA32, 0, DNofill);
+ if(tmp == nil)
+ sysfatal("allocimage: %r");
switch(filter){
case UFScale2x:
@@ -158,8 +179,10 @@ upscaledraw(Raster *fb, Image *dst, Point off, Point scale, uint filter)
filterfn(blk, fb, sp);
else
memsetl(blk, getpixel(fb, sp), scale.x*scale.y);
- loadimage(dst, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4);
+ loadimage(tmp, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4);
}
+ draw(dst, dst->r, tmp, nil, tmp->r.min);
+ freeimage(tmp);
free(blk);
}
@@ -186,6 +209,7 @@ framebufctl_draw(Framebufctl *ctl, Image *dst, char *name, Point off, Point scal
Framebuf *fb;
Raster *r, *r2;
Rectangle sr, dr;
+ Image *tmp;
qlock(ctl);
fb = ctl->getfb(ctl);
@@ -203,10 +227,18 @@ framebufctl_draw(Framebufctl *ctl, Image *dst, char *name, Point off, Point scal
r = r2;
}
+ /* this means the raster is a color one, so duplicate it */
+ if(r2 == nil){
+ r2 = allocraster(nil, r->r, COLOR32);
+ memmove(r2->data, r->data, Dx(r->r)*Dy(r->r)*4);
+ r = r2;
+ }
+ premulalpha(r);
+
if(scale.x > 1 || scale.y > 1){
upscaledraw(r, dst, off, scale, ctl->upfilter);
qunlock(ctl);
- if(r2 != nil) freeraster(r2);
+ freeraster(r2);
return;
}
@@ -259,17 +291,30 @@ framebufctl_draw(Framebufctl *ctl, Image *dst, char *name, Point off, Point scal
// }
// procpoolwait(turbodrawingpool);
// free(tasks);
- loadimage(dst, rectaddpt(sr, dst->r.min), (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4);
+
+ tmp = allocimage(display, sr, RGBA32, 0, DNofill);
+ if(tmp == nil)
+ sysfatal("allocimage: %r");
+
+ loadimage(tmp, sr, (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4);
+ draw(dst, rectaddpt(sr, dst->r.min), tmp, nil, ZP);
+ freeimage(tmp);
}else if(rectclip(&sr, dr)){
+ tmp = allocimage(display, sr, RGBA32, 0, DNofill);
+ if(tmp == nil)
+ sysfatal("allocimage: %r");
+
dr = sr;
dr.max.y = dr.min.y + 1;
/* remove offset to get the actual rect within the framebuffer */
sr = rectsubpt(sr, off);
for(; sr.min.y < sr.max.y; sr.min.y++, dr.min.y++, dr.max.y++)
- loadimage(dst, rectaddpt(dr, dst->r.min), rasterbyteaddr(r, sr.min), Dx(dr)*4);
+ loadimage(tmp, rectaddpt(dr, dst->r.min), rasterbyteaddr(r, sr.min), Dx(dr)*4);
+ draw(dst, rectaddpt(tmp->r, dst->r.min), tmp, nil, tmp->r.min);
+ freeimage(tmp);
}
qunlock(ctl);
- if(r2 != nil) freeraster(r2);
+ freeraster(r2);
}
static void
@@ -278,11 +323,15 @@ upscalememdraw(Raster *fb, Memimage *dst, Point off, Point scale, uint filter)
void (*filterfn)(ulong*, Raster*, Point);
Rectangle blkr;
Point sp, dp;
+ Memimage *tmp;
ulong *blk;
filterfn = nil;
blk = emalloc(scale.x*scale.y*4);
blkr = Rect(0,0,scale.x,scale.y);
+ tmp = allocmemimage(dst->r, RGBA32);
+ if(tmp == nil)
+ sysfatal("allocmemimage: %r");
switch(filter){
case UFScale2x:
@@ -301,8 +350,10 @@ upscalememdraw(Raster *fb, Memimage *dst, Point off, Point scale, uint filter)
filterfn(blk, fb, sp);
else
memsetl(blk, getpixel(fb, sp), scale.x*scale.y);
- loadmemimage(dst, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4);
+ loadmemimage(tmp, rectaddpt(blkr, dp), (uchar*)blk, scale.x*scale.y*4);
}
+ memimagedraw(dst, dst->r, tmp, tmp->r.min, nil, ZP, S);
+ freememimage(tmp);
free(blk);
}
@@ -312,6 +363,7 @@ framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, char *name, Point off, Poin
Framebuf *fb;
Raster *r, *r2;
Rectangle sr, dr;
+ Memimage *tmp;
qlock(ctl);
fb = ctl->getfb(ctl);
@@ -329,27 +381,47 @@ framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, char *name, Point off, Poin
r = r2;
}
+ /* this means the raster is a color one, so duplicate it */
+ if(r2 == nil){
+ r2 = allocraster(nil, r->r, COLOR32);
+ memmove(r2->data, r->data, Dx(r->r)*Dy(r->r)*4);
+ r = r2;
+ }
+ premulalpha(r);
+
if(scale.x > 1 || scale.y > 1){
upscalememdraw(r, dst, off, scale, ctl->upfilter);
qunlock(ctl);
- if(r2 != nil) freeraster(r2);
+ freeraster(r2);
return;
}
sr = rectaddpt(fb->r, off);
dr = rectsubpt(dst->r, dst->r.min);
- if(rectinrect(sr, dr))
- loadmemimage(dst, rectaddpt(sr, dst->r.min), (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4);
- else if(rectclip(&sr, dr)){
+ if(rectinrect(sr, dr)){
+ tmp = allocmemimage(sr, RGBA32);
+ if(tmp == nil)
+ sysfatal("allocmemimage: %r");
+
+ loadmemimage(tmp, sr, (uchar*)r->data, Dx(fb->r)*Dy(r->r)*4);
+ memimagedraw(dst, rectaddpt(sr, dst->r.min), tmp, ZP, nil, ZP, S);
+ freememimage(tmp);
+ }else if(rectclip(&sr, dr)){
+ tmp = allocmemimage(sr, RGBA32);
+ if(tmp == nil)
+ sysfatal("allocmemimage: %r");
+
dr = sr;
dr.max.y = dr.min.y + 1;
/* remove offset to get the actual rect within the framebuffer */
sr = rectsubpt(sr, off);
for(; sr.min.y < sr.max.y; sr.min.y++, dr.min.y++, dr.max.y++)
- loadmemimage(dst, rectaddpt(dr, dst->r.min), rasterbyteaddr(r, sr.min), Dx(dr)*4);
+ loadmemimage(tmp, rectaddpt(dr, dst->r.min), rasterbyteaddr(r, sr.min), Dx(dr)*4);
+ memimagedraw(dst, rectaddpt(tmp->r, dst->r.min), tmp, tmp->r.min, nil, ZP, S);
+ freememimage(tmp);
}
qunlock(ctl);
- if(r2 != nil) freeraster(r2);
+ freeraster(r2);
}
static void
@@ -371,7 +443,7 @@ resetAbuf(Abuf *buf)
}
static void
-framebufctl_reset(Framebufctl *ctl, ulong clr)
+framebufctl_reset(Framebufctl *ctl)
{
Framebuf *fb;
Raster *r;
@@ -381,7 +453,7 @@ framebufctl_reset(Framebufctl *ctl, ulong clr)
resetAbuf(&fb->abuf);
r = fb->rasters; /* color buffer */
- clearraster(r, rgba2xrgb(clr));
+ clearraster(r, 0);
r = r->next; /* z-buffer */
fclearraster(r, Inf(-1));
while((r = r->next) != nil)
@@ -515,6 +587,8 @@ rastergetfloat(Raster *r, Point p)
void
freeraster(Raster *r)
{
+ if(r == nil)
+ return;
free(r->data);
free(r->name);
free(r);
diff --git a/graphics.h b/graphics.h
index 3cd070f..39af008 100644
--- a/graphics.h
+++ b/graphics.h
@@ -24,8 +24,8 @@ enum {
LightSpot,
/* raster formats */
- COLOR32 = 0,
- FLOAT32,
+ COLOR32 = 0, /* RGBA32 */
+ FLOAT32, /* F32 */
/* texture formats */
RAWTexture = 0, /* unmanaged */
@@ -314,7 +314,7 @@ struct Framebufctl
void (*draw)(Framebufctl*, Image*, char*, Point, Point);
void (*memdraw)(Framebufctl*, Memimage*, char*, Point, Point);
void (*swap)(Framebufctl*);
- void (*reset)(Framebufctl*, ulong);
+ void (*reset)(Framebufctl*);
void (*createraster)(Framebufctl*, char*, ulong);
Raster *(*fetchraster)(Framebufctl*, char*);
Framebuf *(*getfb)(Framebufctl*);
@@ -350,7 +350,6 @@ struct Camera
} clip;
Matrix3 proj; /* VCS to clip space xform */
Projection projtype;
- ulong clearcolor;
int cullmode;
int enableblend;
int enabledepth;
@@ -431,14 +430,20 @@ Color samplecubemap(Cubemap*, Point3, Color(*)(Texture*, Point2));
/* util */
Point2 modulapt2(Point2, Point2);
+Point2 minpt2(Point2, Point2);
+Point2 maxpt2(Point2, Point2);
Point3 modulapt3(Point3, Point3);
+Point3 minpt3(Point3, Point3);
+Point3 maxpt3(Point3, Point3);
Memimage *rgb(ulong);
Memimage *dupmemimage(Memimage*);
/* color */
+ulong col2ul(Color);
+Color ul2col(ulong);
+int hasalpha(ulong);
Color srgb2linear(Color);
Color linear2srgb(Color);
-ulong rgba2xrgb(ulong);
Color aces(Color);
Color aces2(Color);
diff --git a/render.c b/render.c
index c86c3d8..9495f30 100644
--- a/render.c
+++ b/render.c
@@ -11,8 +11,6 @@
Rectangle UR = {0,0,1,1};
//Procpool *turbodrawingpool;
-static ulong col2ul(Color);
-
static Vertexattr *
sparams_getuniform(Shaderparams *sp, char *id)
{
@@ -59,30 +57,6 @@ sparams_toraster(Shaderparams *sp, char *rname, void *v)
}
}
-static ulong
-col2ul(Color c)
-{
- uchar cbuf[4];
-
- cbuf[0] = fclamp(c.b, 0, 1)*0xFF;
- cbuf[1] = fclamp(c.g, 0, 1)*0xFF;
- cbuf[2] = fclamp(c.r, 0, 1)*0xFF;
- cbuf[3] = fclamp(c.a, 0, 1)*0xFF;
- return cbuf[3]<<24 | cbuf[2]<<16 | cbuf[1]<<8 | cbuf[0];
-}
-
-static Color
-ul2col(ulong l)
-{
- Color c;
-
- c.b = (l & 0xff)/255.0;
- c.g = (l>>8 & 0xff)/255.0;
- c.r = (l>>16 & 0xff)/255.0;
- c.a = (l>>24 & 0xff)/255.0;
- return c;
-}
-
static void
pixel(Raster *fb, Point p, Color c, int blend)
{
diff --git a/texture.c b/texture.c
index 5d04b89..df5089a 100644
--- a/texture.c
+++ b/texture.c
@@ -48,6 +48,7 @@ _memreadcolor(Texture *t, Point sp)
uchar cbuf[4];
switch(t->image->chan){
+ default: sysfatal("unsupported texture format");
case RGB24:
unloadmemimage(t->image, rectaddpt(UR, sp), cbuf+1, sizeof cbuf - 1);
cbuf[0] = 0xFF;
@@ -63,6 +64,12 @@ _memreadcolor(Texture *t, Point sp)
}
c = cbuf2col(cbuf);
+ /* remove pre-multiplied alpha */
+ if(hasalpha(t->image->chan) && c.a > 0 && c.a < 1){
+ c.r /= c.a;
+ c.g /= c.a;
+ c.b /= c.a;
+ }
switch(t->type){
case sRGBTexture: c = srgb2linear(c); break;
}
diff --git a/util.c b/util.c
index 7335819..e7a9544 100644
--- a/util.c
+++ b/util.c
@@ -14,12 +14,54 @@ modulapt2(Point2 a, Point2 b)
return (Point2){a.x*b.x, a.y*b.y, a.w*b.w};
}
+Point2
+minpt2(Point2 a, Point2 b)
+{
+ return (Point2){
+ min(a.x, b.x),
+ min(a.y, b.y),
+ min(a.w, b.w)
+ };
+}
+
+Point2
+maxpt2(Point2 a, Point2 b)
+{
+ return (Point2){
+ max(a.x, b.x),
+ max(a.y, b.y),
+ max(a.w, b.w)
+ };
+}
+
Point3
modulapt3(Point3 a, Point3 b)
{
return (Point3){a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w};
}
+Point3
+minpt3(Point3 a, Point3 b)
+{
+ return (Point3){
+ min(a.x, b.x),
+ min(a.y, b.y),
+ min(a.z, b.z),
+ min(a.w, b.w)
+ };
+}
+
+Point3
+maxpt3(Point3 a, Point3 b)
+{
+ return (Point3){
+ max(a.x, b.x),
+ max(a.y, b.y),
+ max(a.z, b.z),
+ max(a.w, b.w)
+ };
+}
+
void
memsetf(void *dp, float v, usize len)
{