summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2024-08-07 11:47:31 +0000
committerrodri <rgl@antares-labs.eu>2024-08-07 11:47:31 +0000
commit03149e5536a831e2ea7a20175f04938343529c99 (patch)
tree9494afdaa6be39a528640b2bf43bb773c1b55cf3
parent05ae0d42a944f6c7d940a5e58eb90b619dadbfdb (diff)
downloadlibgraphics-03149e5536a831e2ea7a20175f04938343529c99.tar.gz
libgraphics-03149e5536a831e2ea7a20175f04938343529c99.tar.bz2
libgraphics-03149e5536a831e2ea7a20175f04938343529c99.zip
offset fb during drawing based on viewport config. move OBJ-related procedures to its own unit.
-rw-r--r--fb.c20
-rw-r--r--graphics.h15
-rw-r--r--obj.c317
-rw-r--r--scene.c294
-rw-r--r--viewport.c28
5 files changed, 359 insertions, 315 deletions
diff --git a/fb.c b/fb.c
index 6193a3c..88883fd 100644
--- a/fb.c
+++ b/fb.c
@@ -93,18 +93,18 @@ scale3x_filter(ulong *dst, Framebuf *fb, Point sp)
//}
static void
-framebufctl_draw(Framebufctl *ctl, Image *dst)
+framebufctl_draw(Framebufctl *ctl, Image *dst, Point off)
{
Framebuf *fb;
qlock(ctl);
fb = ctl->getfb(ctl);
- loadimage(dst, rectaddpt(fb->r, dst->r.min), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4);
+ loadimage(dst, rectaddpt(fb->r, addpt(dst->r.min, off)), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4);
qunlock(ctl);
}
static void
-framebufctl_upscaledraw(Framebufctl *ctl, Image *dst, Point scale)
+framebufctl_upscaledraw(Framebufctl *ctl, Image *dst, Point off, Point scale)
{
void (*filter)(ulong*, Framebuf*, Point);
Framebuf *fb;
@@ -130,8 +130,8 @@ framebufctl_upscaledraw(Framebufctl *ctl, Image *dst, Point scale)
break;
}
- for(sp.y = fb->r.min.y, dp.y = dst->r.min.y; sp.y < fb->r.max.y; sp.y++, dp.y += scale.y)
- for(sp.x = fb->r.min.x, dp.x = dst->r.min.x; sp.x < fb->r.max.x; sp.x++, dp.x += scale.x){
+ for(sp.y = fb->r.min.y, dp.y = dst->r.min.y+off.y; sp.y < fb->r.max.y; sp.y++, dp.y += scale.y)
+ for(sp.x = fb->r.min.x, dp.x = dst->r.min.x+off.x; sp.x < fb->r.max.x; sp.x++, dp.x += scale.x){
if(filter != nil)
filter(blk, fb, sp);
else
@@ -143,18 +143,18 @@ framebufctl_upscaledraw(Framebufctl *ctl, Image *dst, Point scale)
}
static void
-framebufctl_memdraw(Framebufctl *ctl, Memimage *dst)
+framebufctl_memdraw(Framebufctl *ctl, Memimage *dst, Point off)
{
Framebuf *fb;
qlock(ctl);
fb = ctl->getfb(ctl);
- loadmemimage(dst, rectaddpt(fb->r, dst->r.min), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4);
+ loadmemimage(dst, rectaddpt(fb->r, addpt(dst->r.min, off)), (uchar*)fb->cb, Dx(fb->r)*Dy(fb->r)*4);
qunlock(ctl);
}
static void
-framebufctl_upscalememdraw(Framebufctl *ctl, Memimage *dst, Point scale)
+framebufctl_upscalememdraw(Framebufctl *ctl, Memimage *dst, Point off, Point scale)
{
void (*filter)(ulong*, Framebuf*, Point);
Framebuf *fb;
@@ -180,8 +180,8 @@ framebufctl_upscalememdraw(Framebufctl *ctl, Memimage *dst, Point scale)
break;
}
- for(sp.y = fb->r.min.y, dp.y = dst->r.min.y; sp.y < fb->r.max.y; sp.y++, dp.y += scale.y)
- for(sp.x = fb->r.min.x, dp.x = dst->r.min.x; sp.x < fb->r.max.x; sp.x++, dp.x += scale.x){
+ for(sp.y = fb->r.min.y, dp.y = dst->r.min.y+off.y; sp.y < fb->r.max.y; sp.y++, dp.y += scale.y)
+ for(sp.x = fb->r.min.x, dp.x = dst->r.min.x+off.x; sp.x < fb->r.max.x; sp.x++, dp.x += scale.x){
if(filter != nil)
filter(blk, fb, sp);
else
diff --git a/graphics.h b/graphics.h
index dfc9f39..4aa18f1 100644
--- a/graphics.h
+++ b/graphics.h
@@ -261,10 +261,10 @@ struct Framebufctl
uint idx; /* front buffer index */
uint upfilter; /* upscaling filter */
- void (*draw)(Framebufctl*, Image*);
- void (*upscaledraw)(Framebufctl*, Image*, Point);
- void (*memdraw)(Framebufctl*, Memimage*);
- void (*upscalememdraw)(Framebufctl*, Memimage*, Point);
+ void (*draw)(Framebufctl*, Image*, Point);
+ void (*upscaledraw)(Framebufctl*, Image*, Point, Point);
+ void (*memdraw)(Framebufctl*, Memimage*, Point);
+ void (*upscalememdraw)(Framebufctl*, Memimage*, Point, Point);
void (*drawnormals)(Framebufctl*, Image*);
void (*swap)(Framebufctl*);
void (*reset)(Framebufctl*);
@@ -283,6 +283,8 @@ struct Viewport
void (*setscale)(Viewport*, double, double);
void (*setscalefilter)(Viewport*, int);
Framebuf *(*getfb)(Viewport*);
+ int (*getwidth)(Viewport*);
+ int (*getheight)(Viewport*);
};
struct Camera
@@ -344,8 +346,11 @@ Point3 world2model(Entity*, Point3);
void perspective(Matrix3, double, double, double, double);
void orthographic(Matrix3, double, double, double, double, double, double);
-/* scene */
+/* obj */
int loadobjmodel(Model*, OBJ*);
+Model *readobjmodel(char*);
+
+/* scene */
Model *newmodel(void);
Model *dupmodel(Model*);
void delmodel(Model*);
diff --git a/obj.c b/obj.c
new file mode 100644
index 0000000..8c7b13f
--- /dev/null
+++ b/obj.c
@@ -0,0 +1,317 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <geometry.h>
+#include "libobj/obj.h"
+#include "graphics.h"
+#include "internal.h"
+
+/*
+ * fan triangulation.
+ *
+ * TODO check that the polygon is in fact convex
+ * try to adapt if not (by finding a convex
+ * vertex), or discard it.
+ */
+static int
+triangulate(OBJElem **newe, OBJElem *e)
+{
+ OBJIndexArray *newidxtab;
+ OBJIndexArray *idxtab;
+ int i;
+
+ idxtab = &e->indextab[OBJVGeometric];
+ for(i = 0; i < idxtab->nindex-2; i++){
+ idxtab = &e->indextab[OBJVGeometric];
+ newe[i] = emalloc(sizeof **newe);
+ memset(newe[i], 0, sizeof **newe);
+ newe[i]->type = OBJEFace;
+ newe[i]->mtl = e->mtl;
+ newidxtab = &newe[i]->indextab[OBJVGeometric];
+ newidxtab->nindex = 3;
+ newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+ newidxtab->indices[0] = idxtab->indices[0];
+ newidxtab->indices[1] = idxtab->indices[i+1];
+ newidxtab->indices[2] = idxtab->indices[i+2];
+ idxtab = &e->indextab[OBJVTexture];
+ if(idxtab->nindex > 0){
+ newidxtab = &newe[i]->indextab[OBJVTexture];
+ newidxtab->nindex = 3;
+ newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+ newidxtab->indices[0] = idxtab->indices[0];
+ newidxtab->indices[1] = idxtab->indices[i+1];
+ newidxtab->indices[2] = idxtab->indices[i+2];
+ }
+ idxtab = &e->indextab[OBJVNormal];
+ if(idxtab->nindex > 0){
+ newidxtab = &newe[i]->indextab[OBJVNormal];
+ newidxtab->nindex = 3;
+ newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
+ newidxtab->indices[0] = idxtab->indices[0];
+ newidxtab->indices[1] = idxtab->indices[i+1];
+ newidxtab->indices[2] = idxtab->indices[i+2];
+ }
+ }
+
+ return i;
+}
+
+typedef struct OBJ2MtlEntry OBJ2MtlEntry;
+typedef struct OBJ2MtlMap OBJ2MtlMap;
+
+struct OBJ2MtlEntry
+{
+ OBJMaterial *objmtl;
+ ulong idx;
+ OBJ2MtlEntry *next;
+};
+
+struct OBJ2MtlMap
+{
+ OBJ2MtlEntry *head;
+ Material *mtls;
+};
+
+static void
+addmtlmap(OBJ2MtlMap *map, OBJMaterial *om, ulong idx)
+{
+ OBJ2MtlEntry *e;
+
+ if(om == nil)
+ return;
+
+ e = emalloc(sizeof *e);
+ memset(e, 0, sizeof *e);
+ e->objmtl = om;
+ e->idx = idx;
+
+ if(map->head == nil){
+ map->head = e;
+ return;
+ }
+
+ e->next = map->head;
+ map->head = e;
+}
+
+static Material *
+getmtlmap(OBJ2MtlMap *map, OBJMaterial *om)
+{
+ OBJ2MtlEntry *e;
+
+ for(e = map->head; e != nil; e = e->next)
+ if(e->objmtl == om)
+ return &map->mtls[e->idx];
+ return nil;
+}
+
+static void
+clrmtlmap(OBJ2MtlMap *map)
+{
+ OBJ2MtlEntry *e, *ne;
+
+ for(e = map->head; e != nil; e = ne){
+ ne = e->next;
+ free(e);
+ }
+}
+
+int
+loadobjmodel(Model *m, OBJ *obj)
+{
+ Primitive *p;
+ OBJVertex *pverts, *tverts, *nverts, *v; /* geometric, texture and normals vertices */
+ OBJElem **trielems, *e, *ne;
+ OBJObject *o;
+ OBJIndexArray *idxtab;
+ OBJ2MtlMap mtlmap;
+ OBJMaterial *objmtl;
+ Material *mtl;
+ Point3 n; /* surface normal */
+ int i, idx, nt, maxnt, neednormal, gottaclean;
+
+ if(obj == nil)
+ return 0;
+
+ pverts = obj->vertdata[OBJVGeometric].verts;
+ tverts = obj->vertdata[OBJVTexture].verts;
+ nverts = obj->vertdata[OBJVNormal].verts;
+ trielems = nil;
+ maxnt = 0;
+
+ if(m->prims != nil){
+ free(m->prims);
+ m->prims = nil;
+ }
+ m->nprims = 0;
+
+ mtlmap.head = nil;
+ for(i = 0; obj->materials != nil && i < nelem(obj->materials->mattab); i++)
+ for(objmtl = obj->materials->mattab[i]; objmtl != nil; objmtl = objmtl->next){
+ mtlmap.mtls = m->materials = erealloc(m->materials, ++m->nmaterials*sizeof(*m->materials));
+ mtl = &m->materials[m->nmaterials-1];
+ memset(mtl, 0, sizeof *mtl);
+
+ if(objmtl->name != nil){
+ mtl->name = strdup(objmtl->name);
+ if(mtl->name == nil)
+ sysfatal("strdup: %r");
+ }
+ mtl->ambient = Pt3(objmtl->Ka.r, objmtl->Ka.g, objmtl->Ka.b, 1);
+ mtl->diffuse = Pt3(objmtl->Kd.r, objmtl->Kd.g, objmtl->Kd.b, 1);
+ mtl->specular = Pt3(objmtl->Ks.r, objmtl->Ks.g, objmtl->Ks.b, 1);
+ mtl->shininess = objmtl->Ns;
+
+ if(objmtl->map_Kd != nil){
+ mtl->diffusemap = alloctexture(sRGBTexture, nil);
+ mtl->diffusemap->image = dupmemimage(objmtl->map_Kd);
+ }
+
+ if(objmtl->norm != nil){
+ mtl->normalmap = alloctexture(RAWTexture, nil);
+ mtl->normalmap->image = dupmemimage(objmtl->norm);
+ }
+
+ addmtlmap(&mtlmap, objmtl, m->nmaterials-1);
+ }
+
+ for(i = 0; i < nelem(obj->objtab); i++)
+ for(o = obj->objtab[i]; o != nil; o = o->next)
+ for(e = o->child; e != nil; e = ne){
+ ne = e->next;
+
+ switch(e->type){
+ case OBJEPoint:
+ m->prims = erealloc(m->prims, ++m->nprims*sizeof(*m->prims));
+ p = &m->prims[m->nprims-1];
+ memset(p, 0, sizeof *p);
+ p->type = PPoint;
+ p->mtl = getmtlmap(&mtlmap, e->mtl);
+
+ idxtab = &e->indextab[OBJVGeometric];
+ v = &pverts[idxtab->indices[0]];
+ p->v[0].p = Pt3(v->x, v->y, v->z, v->w);
+
+ idxtab = &e->indextab[OBJVTexture];
+ if(idxtab->nindex == 1){
+ v = &tverts[idxtab->indices[0]];
+ p->v[0].uv = Pt2(v->u, v->v, 1);
+ }
+ break;
+ case OBJELine:
+ m->prims = erealloc(m->prims, ++m->nprims*sizeof(*m->prims));
+ p = &m->prims[m->nprims-1];
+ memset(p, 0, sizeof *p);
+ p->type = PLine;
+ p->mtl = getmtlmap(&mtlmap, e->mtl);
+
+ for(idx = 0; idx < 2; idx++){
+ idxtab = &e->indextab[OBJVGeometric];
+ v = &pverts[idxtab->indices[idx]];
+ p->v[idx].p = Pt3(v->x, v->y, v->z, v->w);
+
+ idxtab = &e->indextab[OBJVTexture];
+ if(idxtab->nindex == 2){
+ v = &tverts[idxtab->indices[idx]];
+ p->v[idx].uv = Pt2(v->u, v->v, 1);
+ }
+ }
+ break;
+ case OBJEFace:
+ idxtab = &e->indextab[OBJVGeometric];
+ assert(idxtab->nindex >= 3);
+ gottaclean = 0;
+
+ /* it takes n-2 triangles to fill any given n-gon */
+ nt = idxtab->nindex-2;
+ if(nt > maxnt){
+ maxnt = nt;
+ trielems = erealloc(trielems, maxnt*sizeof(*trielems));
+ }
+ if(nt > 1){
+ assert(triangulate(trielems, e) == nt);
+ gottaclean = 1;
+ }else
+ trielems[0] = e;
+
+ while(nt-- > 0){
+ e = trielems[nt];
+ neednormal = 0;
+
+ m->prims = erealloc(m->prims, ++m->nprims*sizeof(*m->prims));
+ p = &m->prims[m->nprims-1];
+ memset(p, 0, sizeof *p);
+ p->type = PTriangle;
+ p->mtl = getmtlmap(&mtlmap, e->mtl);
+
+ for(idx = 0; idx < 3; idx++){
+ idxtab = &e->indextab[OBJVGeometric];
+ v = &pverts[idxtab->indices[idx]];
+ p->v[idx].p = Pt3(v->x, v->y, v->z, v->w);
+
+ idxtab = &e->indextab[OBJVNormal];
+ if(idxtab->nindex == 3){
+ v = &nverts[idxtab->indices[idx]];
+ p->v[idx].n = normvec3(Vec3(v->i, v->j, v->k));
+ }else
+ neednormal = 1;
+
+ idxtab = &e->indextab[OBJVTexture];
+ if(idxtab->nindex == 3){
+ v = &tverts[idxtab->indices[idx]];
+ p->v[idx].uv = Pt2(v->u, v->v, 1);
+ }
+ }
+ if(p->v[0].uv.w != 0){
+ Point3 e0, e1;
+ Point2 Δuv0, Δuv1;
+ double det;
+
+ e0 = subpt3(p->v[1].p, p->v[0].p);
+ e1 = subpt3(p->v[2].p, p->v[0].p);
+ Δuv0 = subpt2(p->v[1].uv, p->v[0].uv);
+ Δuv1 = subpt2(p->v[2].uv, p->v[0].uv);
+
+ det = Δuv0.x * Δuv1.y - Δuv1.x * Δuv0.y;
+ det = det == 0? 0: 1.0/det;
+ p->tangent.x = det*(Δuv1.y * e0.x - Δuv0.y * e1.x);
+ p->tangent.y = det*(Δuv1.y * e0.y - Δuv0.y * e1.y);
+ p->tangent.z = det*(Δuv1.y * e0.z - Δuv0.y * e1.z);
+ p->tangent = normvec3(p->tangent);
+ }
+ if(neednormal){
+ n = normvec3(crossvec3(subpt3(p->v[1].p, p->v[0].p), subpt3(p->v[2].p, p->v[0].p)));
+ p->v[0].n = p->v[1].n = p->v[2].n = n;
+ }
+ if(gottaclean){
+ free(e->indextab[OBJVGeometric].indices);
+ free(e->indextab[OBJVNormal].indices);
+ free(e->indextab[OBJVTexture].indices);
+ free(e);
+ }
+ }
+ break;
+ default: continue;
+ }
+ }
+
+ free(trielems);
+ clrmtlmap(&mtlmap);
+ return m->nprims;
+}
+
+Model *
+readobjmodel(char *path)
+{
+ Model *m;
+ OBJ *obj;
+
+ m = newmodel();
+ if((obj = objparse(path)) == nil)
+ sysfatal("objparse: %r");
+ loadobjmodel(m, obj);
+ objfree(obj);
+ return m;
+}
diff --git a/scene.c b/scene.c
index 8a05bc9..d4d1872 100644
--- a/scene.c
+++ b/scene.c
@@ -8,300 +8,6 @@
#include "graphics.h"
#include "internal.h"
-/*
- * fan triangulation.
- *
- * TODO check that the polygon is in fact convex
- * try to adapt if not (by finding a convex
- * vertex), or discard it.
- */
-static int
-triangulate(OBJElem **newe, OBJElem *e)
-{
- OBJIndexArray *newidxtab;
- OBJIndexArray *idxtab;
- int i;
-
- idxtab = &e->indextab[OBJVGeometric];
- for(i = 0; i < idxtab->nindex-2; i++){
- idxtab = &e->indextab[OBJVGeometric];
- newe[i] = emalloc(sizeof **newe);
- memset(newe[i], 0, sizeof **newe);
- newe[i]->type = OBJEFace;
- newe[i]->mtl = e->mtl;
- newidxtab = &newe[i]->indextab[OBJVGeometric];
- newidxtab->nindex = 3;
- newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
- newidxtab->indices[0] = idxtab->indices[0];
- newidxtab->indices[1] = idxtab->indices[i+1];
- newidxtab->indices[2] = idxtab->indices[i+2];
- idxtab = &e->indextab[OBJVTexture];
- if(idxtab->nindex > 0){
- newidxtab = &newe[i]->indextab[OBJVTexture];
- newidxtab->nindex = 3;
- newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
- newidxtab->indices[0] = idxtab->indices[0];
- newidxtab->indices[1] = idxtab->indices[i+1];
- newidxtab->indices[2] = idxtab->indices[i+2];
- }
- idxtab = &e->indextab[OBJVNormal];
- if(idxtab->nindex > 0){
- newidxtab = &newe[i]->indextab[OBJVNormal];
- newidxtab->nindex = 3;
- newidxtab->indices = emalloc(newidxtab->nindex*sizeof(*newidxtab->indices));
- newidxtab->indices[0] = idxtab->indices[0];
- newidxtab->indices[1] = idxtab->indices[i+1];
- newidxtab->indices[2] = idxtab->indices[i+2];
- }
- }
-
- return i;
-}
-
-typedef struct OBJ2MtlEntry OBJ2MtlEntry;
-typedef struct OBJ2MtlMap OBJ2MtlMap;
-
-struct OBJ2MtlEntry
-{
- OBJMaterial *objmtl;
- ulong idx;
- OBJ2MtlEntry *next;
-};
-
-struct OBJ2MtlMap
-{
- OBJ2MtlEntry *head;
- Material *mtls;
-};
-
-static void
-addmtlmap(OBJ2MtlMap *map, OBJMaterial *om, ulong idx)
-{
- OBJ2MtlEntry *e;
-
- if(om == nil)
- return;
-
- e = emalloc(sizeof *e);
- memset(e, 0, sizeof *e);
- e->objmtl = om;
- e->idx = idx;
-
- if(map->head == nil){
- map->head = e;
- return;
- }
-
- e->next = map->head;
- map->head = e;
-}
-
-static Material *
-getmtlmap(OBJ2MtlMap *map, OBJMaterial *om)
-{
- OBJ2MtlEntry *e;
-
- for(e = map->head; e != nil; e = e->next)
- if(e->objmtl == om)
- return &map->mtls[e->idx];
- return nil;
-}
-
-static void
-clrmtlmap(OBJ2MtlMap *map)
-{
- OBJ2MtlEntry *e, *ne;
-
- for(e = map->head; e != nil; e = ne){
- ne = e->next;
- free(e);
- }
-}
-
-int
-loadobjmodel(Model *m, OBJ *obj)
-{
- Primitive *p;
- OBJVertex *pverts, *tverts, *nverts, *v; /* geometric, texture and normals vertices */
- OBJElem **trielems, *e, *ne;
- OBJObject *o;
- OBJIndexArray *idxtab;
- OBJ2MtlMap mtlmap;
- OBJMaterial *objmtl;
- Material *mtl;
- Point3 n; /* surface normal */
- int i, idx, nt, maxnt, neednormal, gottaclean;
-
- if(obj == nil)
- return 0;
-
- pverts = obj->vertdata[OBJVGeometric].verts;
- tverts = obj->vertdata[OBJVTexture].verts;
- nverts = obj->vertdata[OBJVNormal].verts;
- trielems = nil;
- maxnt = 0;
-
- if(m->prims != nil){
- free(m->prims);
- m->prims = nil;
- }
- m->nprims = 0;
-
- mtlmap.head = nil;
- for(i = 0; obj->materials != nil && i < nelem(obj->materials->mattab); i++)
- for(objmtl = obj->materials->mattab[i]; objmtl != nil; objmtl = objmtl->next){
- mtlmap.mtls = m->materials = erealloc(m->materials, ++m->nmaterials*sizeof(*m->materials));
- mtl = &m->materials[m->nmaterials-1];
- memset(mtl, 0, sizeof *mtl);
-
- if(objmtl->name != nil){
- mtl->name = strdup(objmtl->name);
- if(mtl->name == nil)
- sysfatal("strdup: %r");
- }
- mtl->ambient = Pt3(objmtl->Ka.r, objmtl->Ka.g, objmtl->Ka.b, 1);
- mtl->diffuse = Pt3(objmtl->Kd.r, objmtl->Kd.g, objmtl->Kd.b, 1);
- mtl->specular = Pt3(objmtl->Ks.r, objmtl->Ks.g, objmtl->Ks.b, 1);
- mtl->shininess = objmtl->Ns;
-
- if(objmtl->map_Kd != nil){
- mtl->diffusemap = alloctexture(sRGBTexture, nil);
- mtl->diffusemap->image = dupmemimage(objmtl->map_Kd);
- }
-
- if(objmtl->norm != nil){
- mtl->normalmap = alloctexture(RAWTexture, nil);
- mtl->normalmap->image = dupmemimage(objmtl->norm);
- }
-
- addmtlmap(&mtlmap, objmtl, m->nmaterials-1);
- }
-
- for(i = 0; i < nelem(obj->objtab); i++)
- for(o = obj->objtab[i]; o != nil; o = o->next)
- for(e = o->child; e != nil; e = ne){
- ne = e->next;
-
- switch(e->type){
- case OBJEPoint:
- m->prims = erealloc(m->prims, ++m->nprims*sizeof(*m->prims));
- p = &m->prims[m->nprims-1];
- memset(p, 0, sizeof *p);
- p->type = PPoint;
- p->mtl = getmtlmap(&mtlmap, e->mtl);
-
- idxtab = &e->indextab[OBJVGeometric];
- v = &pverts[idxtab->indices[0]];
- p->v[0].p = Pt3(v->x, v->y, v->z, v->w);
-
- idxtab = &e->indextab[OBJVTexture];
- if(idxtab->nindex == 1){
- v = &tverts[idxtab->indices[0]];
- p->v[0].uv = Pt2(v->u, v->v, 1);
- }
- break;
- case OBJELine:
- m->prims = erealloc(m->prims, ++m->nprims*sizeof(*m->prims));
- p = &m->prims[m->nprims-1];
- memset(p, 0, sizeof *p);
- p->type = PLine;
- p->mtl = getmtlmap(&mtlmap, e->mtl);
-
- for(idx = 0; idx < 2; idx++){
- idxtab = &e->indextab[OBJVGeometric];
- v = &pverts[idxtab->indices[idx]];
- p->v[idx].p = Pt3(v->x, v->y, v->z, v->w);
-
- idxtab = &e->indextab[OBJVTexture];
- if(idxtab->nindex == 2){
- v = &tverts[idxtab->indices[idx]];
- p->v[idx].uv = Pt2(v->u, v->v, 1);
- }
- }
- break;
- case OBJEFace:
- idxtab = &e->indextab[OBJVGeometric];
- assert(idxtab->nindex >= 3);
- gottaclean = 0;
-
- /* it takes n-2 triangles to fill any given n-gon */
- nt = idxtab->nindex-2;
- if(nt > maxnt){
- maxnt = nt;
- trielems = erealloc(trielems, maxnt*sizeof(*trielems));
- }
- if(nt > 1){
- assert(triangulate(trielems, e) == nt);
- gottaclean = 1;
- }else
- trielems[0] = e;
-
- while(nt-- > 0){
- e = trielems[nt];
- neednormal = 0;
-
- m->prims = erealloc(m->prims, ++m->nprims*sizeof(*m->prims));
- p = &m->prims[m->nprims-1];
- memset(p, 0, sizeof *p);
- p->type = PTriangle;
- p->mtl = getmtlmap(&mtlmap, e->mtl);
-
- for(idx = 0; idx < 3; idx++){
- idxtab = &e->indextab[OBJVGeometric];
- v = &pverts[idxtab->indices[idx]];
- p->v[idx].p = Pt3(v->x, v->y, v->z, v->w);
-
- idxtab = &e->indextab[OBJVNormal];
- if(idxtab->nindex == 3){
- v = &nverts[idxtab->indices[idx]];
- p->v[idx].n = normvec3(Vec3(v->i, v->j, v->k));
- }else
- neednormal = 1;
-
- idxtab = &e->indextab[OBJVTexture];
- if(idxtab->nindex == 3){
- v = &tverts[idxtab->indices[idx]];
- p->v[idx].uv = Pt2(v->u, v->v, 1);
- }
- }
- if(p->v[0].uv.w != 0){
- Point3 e0, e1;
- Point2 Δuv0, Δuv1;
- double det;
-
- e0 = subpt3(p->v[1].p, p->v[0].p);
- e1 = subpt3(p->v[2].p, p->v[0].p);
- Δuv0 = subpt2(p->v[1].uv, p->v[0].uv);
- Δuv1 = subpt2(p->v[2].uv, p->v[0].uv);
-
- det = Δuv0.x * Δuv1.y - Δuv1.x * Δuv0.y;
- det = det == 0? 0: 1.0/det;
- p->tangent.x = det*(Δuv1.y * e0.x - Δuv0.y * e1.x);
- p->tangent.y = det*(Δuv1.y * e0.y - Δuv0.y * e1.y);
- p->tangent.z = det*(Δuv1.y * e0.z - Δuv0.y * e1.z);
- p->tangent = normvec3(p->tangent);
- }
- if(neednormal){
- n = normvec3(crossvec3(subpt3(p->v[1].p, p->v[0].p), subpt3(p->v[2].p, p->v[0].p)));
- p->v[0].n = p->v[1].n = p->v[2].n = n;
- }
- if(gottaclean){
- free(e->indextab[OBJVGeometric].indices);
- free(e->indextab[OBJVNormal].indices);
- free(e->indextab[OBJVTexture].indices);
- free(e);
- }
- }
- break;
- default: continue;
- }
- }
-
- free(trielems);
- clrmtlmap(&mtlmap);
- return m->nprims;
-}
-
Model *
newmodel(void)
{
diff --git a/viewport.c b/viewport.c
index b3be122..9e41e53 100644
--- a/viewport.c
+++ b/viewport.c
@@ -11,31 +11,33 @@
static void
viewport_draw(Viewport *v, Image *dst)
{
- Point scale;
+ Point off, scale;
+ off = Pt(v->p.x, v->p.y);
/* no downsampling support yet */
scale.x = max(min(v->bx.x, Dx(dst->r)/Dx(v->r)), 1);
scale.y = max(min(v->by.y, Dy(dst->r)/Dy(v->r)), 1);
if(scale.x > 1 || scale.y > 1)
- v->fbctl->upscaledraw(v->fbctl, dst, scale);
+ v->fbctl->upscaledraw(v->fbctl, dst, off, scale);
else
- v->fbctl->draw(v->fbctl, dst);
+ v->fbctl->draw(v->fbctl, dst, off);
}
static void
viewport_memdraw(Viewport *v, Memimage *dst)
{
- Point scale;
+ Point off, scale;
+ off = Pt(v->p.x, v->p.y);
/* no downsampling support yet */
scale.x = max(min(v->bx.x, Dx(dst->r)/Dx(v->r)), 1);
scale.y = max(min(v->by.y, Dy(dst->r)/Dy(v->r)), 1);
if(scale.x > 1 || scale.y > 1)
- v->fbctl->upscalememdraw(v->fbctl, dst, scale);
+ v->fbctl->upscalememdraw(v->fbctl, dst, off, scale);
else
- v->fbctl->memdraw(v->fbctl, dst);
+ v->fbctl->memdraw(v->fbctl, dst, off);
}
static void
@@ -59,6 +61,18 @@ viewport_getfb(Viewport *v)
return v->fbctl->getfb(v->fbctl);
}
+static int
+viewport_getwidth(Viewport *v)
+{
+ return Dx(v->r)*v->bx.x;
+}
+
+static int
+viewport_getheight(Viewport *v)
+{
+ return Dy(v->r)*v->by.y;
+}
+
Viewport *
mkviewport(Rectangle r)
{
@@ -75,6 +89,8 @@ mkviewport(Rectangle r)
v->setscale = viewport_setscale;
v->setscalefilter = viewport_setscalefilter;
v->getfb = viewport_getfb;
+ v->getwidth = viewport_getwidth;
+ v->getheight = viewport_getheight;
return v;
}