I guess I can just put this up. Most of these have been sitting here forever.

This commit is contained in:
Marisa the Magician 2017-09-04 11:24:40 +02:00
commit d2777092d1
26 changed files with 5347 additions and 0 deletions

437
osnorm.c Normal file
View file

@ -0,0 +1,437 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define dword __UINT32_TYPE__
#define byte __UINT8_TYPE__
typedef struct
{
char magic[4];
dword size, flags, height, width, pitch, depth, mipmaps, reserved1[11],
pf_size, pf_flags;
char pf_fourcc[4];
dword pf_bitcount, pf_rmask, pf_gmask, pf_bmask, pf_amask, caps[4],
reserved2;
} __attribute__((packed)) ddsheader_t;
ddsheader_t head =
{
.magic = "DDS ", .size = 124,
.flags = 0x0000100F, /* caps|height|width|pitch|pixelformat */
.height = 0, .width = 0, .pitch = 0, .depth = 0, /* set later */
.mipmaps = 0, .reserved1 = {0,0,0,0,0,0,0,0,0,0,0}, .pf_size = 32,
.pf_flags = 0x41 /* uncompressed|alpha */, .pf_fourcc = {0}, /* N/A */
.pf_bitcount = 32, .pf_rmask = 0xff, .pf_gmask = 0xff00,
.pf_bmask = 0xff0000, .pf_amask = 0xff000000, /* RGBA mask */
.caps = {0x1000,0,0,0}, /* texture */ .reserved2 = 0
};
typedef struct { byte r,g,b,a; } __attribute__((packed)) pixel_t;
unsigned w = 0, h = 0;
pixel_t *tex = 0, *ttex = 0;
FILE *obj, *dds, *tmap;
typedef struct { float x,y,z; } vect_t;
typedef struct { float u,v; } uv_t;
typedef struct { int v,c,n; } vert_t;
typedef struct { vert_t a,b,c; } tri_t;
typedef struct { int x,y; } vec2_t;
typedef struct { pixel_t c[2]; vec2_t p[2]; } edge_t;
vect_t *verts = 0, *norms = 0, *tangents = 0, *binormals = 0;
uv_t *uvs = 0;
tri_t *tris = 0;
int nvert = 0, nnorm = 0, ncoord = 0, nface = 0;
void cross( vect_t *a, vect_t b, vect_t c )
{
a->x = b.y*c.z-b.z*c.y;
a->y = b.z*c.x-b.x*c.z;
a->z = b.x*c.y-b.y*c.x;
}
void normalize( vect_t *a )
{
float scale = sqrtf(powf(a->x,2.f)+powf(a->y,2.f)+powf(a->z,2.f));
a->x /= scale;
a->y /= scale;
a->z /= scale;
}
void normalize2( uv_t *a )
{
float scale = sqrtf(powf(a->u,2.f)+powf(a->v,2.f));
a->u /= scale;
a->v /= scale;
}
float dot( vect_t a, vect_t b )
{
return a.x*b.x+a.y*b.y+a.z*b.z;
}
void tangent( vect_t *t, vect_t *b, int n )
{
vect_t t1 = {0,0,0}, t2 = {0,0,0};
for ( int j=0; j<nface; j++ )
{
if ( (tris[j].a.n != n) && (tris[j].b.n != n)
&& (tris[j].c.n != n) ) continue;
}
}
void calctangents( void )
{
if ( tangents ) free(tangents);
if ( binormals ) free(binormals);
tangents = malloc(sizeof(vect_t)*nnorm);
binormals = malloc(sizeof(vect_t)*nnorm);
memset(tangents,0,sizeof(vect_t)*nnorm);
memset(binormals,0,sizeof(vect_t)*nnorm);
vect_t *t1, *t2;
t1 = malloc(sizeof(vect_t)*nnorm);
t2 = malloc(sizeof(vect_t)*nnorm);
memset(t1,0,sizeof(vect_t)*nnorm);
memset(t2,0,sizeof(vect_t)*nnorm);
for ( int j=0; j<nface; j++ )
{
vect_t abv, acv;
uv_t abc, acc;
float r;
vect_t ud, vd;
abv.x = verts[tris[j].b.v].x-verts[tris[j].a.v].x;
abv.y = verts[tris[j].b.v].y-verts[tris[j].a.v].y;
abv.z = verts[tris[j].b.v].z-verts[tris[j].a.v].z;
acv.x = verts[tris[j].c.v].x-verts[tris[j].a.v].x;
acv.y = verts[tris[j].c.v].y-verts[tris[j].a.v].y;
acv.z = verts[tris[j].c.v].z-verts[tris[j].a.v].z;
abc.u = uvs[tris[j].b.c].u-uvs[tris[j].a.c].u;
abc.v = uvs[tris[j].b.c].v-uvs[tris[j].a.c].v;
acc.u = uvs[tris[j].c.c].u-uvs[tris[j].a.c].u;
acc.v = uvs[tris[j].c.c].v-uvs[tris[j].a.c].v;
r = 1.f/(abc.u*acc.v-acc.u*abc.v);
ud.x = (acc.v*abv.x-abc.v-acv.x)*r;
ud.y = (acc.v*abv.y-abc.v-acv.y)*r;
ud.z = (acc.v*abv.z-abc.v-acv.z)*r;
vd.x = (abc.u*acv.x-acc.u-abv.x)*r;
vd.y = (abc.u*acv.y-acc.u-abv.y)*r;
vd.z = (abc.u*acv.z-acc.u-abv.z)*r;
t1[tris[j].a.n].x += ud.x;
t1[tris[j].a.n].y += ud.y;
t1[tris[j].a.n].z += ud.z;
t1[tris[j].b.n].x += ud.x;
t1[tris[j].b.n].y += ud.y;
t1[tris[j].b.n].z += ud.z;
t1[tris[j].c.n].x += ud.x;
t1[tris[j].c.n].y += ud.y;
t1[tris[j].c.n].z += ud.z;
t2[tris[j].a.n].x += vd.x;
t2[tris[j].a.n].y += vd.y;
t2[tris[j].a.n].z += vd.z;
t2[tris[j].b.n].x += vd.x;
t2[tris[j].b.n].y += vd.y;
t2[tris[j].b.n].z += vd.z;
t2[tris[j].c.n].x += vd.x;
t2[tris[j].c.n].y += vd.y;
t2[tris[j].c.n].z += vd.z;
}
for ( int i=0; i<nnorm; i++ )
{
float dotnt = dot(norms[i],t1[i]);
tangents[i].x = t1[i].x-norms[i].x*dotnt;
tangents[i].y = t1[i].y-norms[i].y*dotnt;
tangents[i].z = t1[i].z-norms[i].z*dotnt;
normalize(&tangents[i]);
cross(&binormals[i],norms[i],t1[i]);
float hand = (dot(binormals[i],t2[i])<0.f)?-1.f:1.f;
binormals[i].x *= hand;
binormals[i].y *= hand;
binormals[i].z *= hand;
}
free(t1);
free(t2);
}
void calcnormals( void )
{
if ( norms ) free(norms);
norms = malloc(sizeof(vect_t)*nvert);
memset(norms,0,sizeof(vect_t)*nvert);
nnorm = nvert;
for ( int i=0; i<nface; i++ )
{
tris[i].a.n = tris[i].a.v;
tris[i].b.n = tris[i].b.v;
tris[i].c.n = tris[i].c.v;
}
for ( int i=0; i<nvert; i++ )
{
for ( int j=0; j<nface; j++ )
{
if ( (tris[j].a.v != i) && (tris[j].b.v != i)
&& (tris[j].c.v != i) ) continue;
vect_t facet, ab, ac;
ab.x = verts[tris[j].b.v].x-verts[tris[j].a.v].x;
ab.y = verts[tris[j].b.v].y-verts[tris[j].a.v].y;
ab.z = verts[tris[j].b.v].z-verts[tris[j].a.v].z;
ac.x = verts[tris[j].c.v].x-verts[tris[j].a.v].x;
ac.y = verts[tris[j].c.v].y-verts[tris[j].a.v].y;
ac.z = verts[tris[j].c.v].z-verts[tris[j].a.v].z;
cross(&facet,ab,ac);
normalize(&facet);
norms[i].x += facet.x;
norms[i].y += facet.y;
norms[i].z += facet.z;
}
normalize(&norms[i]);
}
}
void loadobj( void )
{
char rbuf[131072];
char *txt = 0;
size_t nread, len = 0, pos = 0;
fseek(obj,0,SEEK_END);
len = ftell(obj);
fseek(obj,0,SEEK_SET);
txt = malloc(len+1);
do
{
nread = fread(rbuf,1,131072,obj);
memcpy(txt+pos,rbuf,nread);
pos += nread;
}
while ( !feof(obj) );
txt[pos] = 0;
char *line = txt;
do
{
if ( !strncmp(line,"v ",2) ) nvert++;
else if ( !strncmp(line,"vt ",3) ) ncoord++;
else if ( !strncmp(line,"vn ",3) ) nnorm++;
else if ( !strncmp(line,"f ",2) ) nface++;
line = strchr(line,'\n');
}
while ( line && *(line++) );
verts = malloc(sizeof(vect_t)*nvert);
norms = malloc(sizeof(vect_t)*nnorm);
uvs = malloc(sizeof(uv_t)*ncoord);
tris = malloc(sizeof(tri_t)*nface);
memset(verts,0,sizeof(vect_t)*nvert);
memset(norms,0,sizeof(vect_t)*nnorm);
memset(uvs,0,sizeof(uv_t)*ncoord);
memset(tris,0,sizeof(tri_t)*nface);
int cv = 0, cc = 0, cn = 0, cf = 0;
line = strtok(txt,"\n");
do
{
if ( !strncmp(line,"v ",2) )
{
sscanf(line,"v %f %f %f",&verts[cv].x,&verts[cv].y,
&verts[cv].z);
cv++;
}
else if ( !strncmp(line,"vt ",3) )
{
sscanf(line,"vt %f %f",&uvs[cc].u,&uvs[cc].v);
uvs[cc].v = 1.0-uvs[cc].v;
cc++;
}
else if ( !strncmp(line,"vn ",3) )
{
sscanf(line,"vn %f %f %f",&norms[cn].x,&norms[cn].y,
&norms[cn].z);
cn++;
}
else if ( !strncmp(line,"f ",2) )
{
if ( cn <= 0 )
{
sscanf(line,"f %d/%d %d/%d %d/%d",
&tris[cf].a.v,&tris[cf].a.c,
&tris[cf].b.v,&tris[cf].b.c,
&tris[cf].c.v,&tris[cf].c.c);
}
else
{
sscanf(line,"f %d/%d/%d %d/%d/%d %d/%d/%d",
&tris[cf].a.v,&tris[cf].a.c,
&tris[cf].a.n,&tris[cf].b.v,
&tris[cf].b.c,&tris[cf].b.n,
&tris[cf].c.v,&tris[cf].c.c,
&tris[cf].c.n);
}
tris[cf].a.v--;
tris[cf].a.c--;
tris[cf].a.n--;
tris[cf].b.v--;
tris[cf].b.c--;
tris[cf].b.n--;
tris[cf].c.v--;
tris[cf].c.c--;
tris[cf].c.n--;
cf++;
}
}
while ( (line = strtok(0,"\n")) );
free(txt);
}
void mkedge( edge_t *e, pixel_t c1, vec2_t p1, pixel_t c2, vec2_t p2 )
{
if ( p1.y < p2.y )
{
e->c[0] = c1;
e->p[0] = p1;
e->c[1] = c2;
e->p[1] = p2;
}
else
{
e->c[0] = c2;
e->p[0] = p2;
e->c[1] = c1;
e->p[1] = p1;
}
}
void lerpcolor( pixel_t *o, pixel_t a, pixel_t b, float f )
{
f = (f>0.f)?(f>1.f)?1.f:f:0.f;
o->r = a.r*(1.f-f)+b.r*f;
o->g = a.g*(1.f-f)+b.g*f;
o->b = a.b*(1.f-f)+b.b*f;
o->a = a.a*(1.f-f)+b.a*f;
}
void drawspans( edge_t a, edge_t b )
{
float e1 = a.p[1].y-a.p[0].y;
if ( e1 == 0.f ) return;
float e2 = b.p[1].y-b.p[0].y;
if ( e2 == 0.f ) return;
float is1 = (float)(a.p[1].x-a.p[0].x);
float is2 = (float)(b.p[1].x-b.p[0].x);
float f1 = (float)(b.p[0].y-a.p[0].y)/e1;
float fs1 = 1.f/e1;
float f2 = 0.f;
float fs2 = 1.f/e2;
for ( int y=b.p[0].y; y<b.p[1].y; y++ )
{
pixel_t c1, c2, c3;
lerpcolor(&c1,a.c[0],a.c[1],f1);
lerpcolor(&c2,b.c[0],b.c[1],f2);
int x1 = a.p[0].x+(int)(is1*f1);
int x2 = b.p[0].x+(int)(is2*f2);
if ( x1>x2 )
{
int tmp = x1;
x1 = x2;
x2 = tmp;
pixel_t tmpc = c1;
c1 = c2;
c2 = tmpc;
}
int xd = x2-x1;
if ( xd != 0 )
{
float fx = 0.f, fsx = 1.f/(float)xd;
for ( int x=x1; x<x2; x++ )
{
lerpcolor(&c3,c1,c2,fx);
if ( (x >= 0) && (x < w) && (y >= 0)
&& (y < h) )
if ( !tex[x+y*w].a ) tex[x+y*w] = c3;
fx += fsx;
}
}
f1 += fs1;
f2 += fs2;
}
}
void drawtriangle( int t1, int t2, int t3, int n1, int n2, int n3 )
{
pixel_t col[3] =
{
{(norms[n1].x*0.5f+0.5f)*255,(norms[n1].z*0.5f+0.5f)*255,
(norms[n1].y*0.5+0.5)*255,255},
{(norms[n2].x*0.5f+0.5f)*255,(norms[n2].z*0.5f+0.5f)*255,
(norms[n2].y*0.5+0.5)*255,255},
{(norms[n3].x*0.5f+0.5f)*255,(norms[n3].z*0.5f+0.5f)*255,
(norms[n3].y*0.5f+0.5f)*255,255},
};
vec2_t pts[3] =
{
{uvs[t1].u*w,uvs[t1].v*h},
{uvs[t2].u*w,uvs[t2].v*h},
{uvs[t3].u*w,uvs[t3].v*h}
};
edge_t edges[3];
mkedge(&edges[0],col[0],pts[0],col[1],pts[1]);
mkedge(&edges[1],col[1],pts[1],col[2],pts[2]);
mkedge(&edges[2],col[2],pts[2],col[0],pts[0]);
float ml = 0;
int longest = 0, short1 = 0, short2 = 0;
for ( int i=0; i<3; i++ )
{
float l = edges[i].p[1].y-edges[i].p[0].y;
if ( l > ml )
{
ml = l;
longest = i;
}
}
short1 = (longest+1)%3;
short2 = (longest+2)%3;
drawspans(edges[longest],edges[short1]);
drawspans(edges[longest],edges[short2]);
}
void plotnormals( void )
{
int x1, y1, x2, y2, x3, y3;
for ( int i=0; i<nface; i++ )
drawtriangle(tris[i].a.c,tris[i].b.c,tris[i].c.c,
tris[i].a.n,tris[i].b.n,tris[i].c.n);
}
int main( int argc, char **argv )
{
if ( argc < 4 ) return 1;
sscanf(argv[3],"%ux%u",&w,&h);
head.width = w;
head.height = h;
head.pitch = w*4;
/* load model */
if ( !(obj = fopen(argv[1],"r")) ) return 2;
loadobj();
fclose(obj);
/* plot pixels */
tex = malloc(sizeof(pixel_t)*w*h);
memset(tex,0,sizeof(pixel_t)*w*h);
printf("calculate normals\n");
calcnormals();
printf("calculate tangents and binormals\n");
calctangents();
printf("plot normals\n");
plotnormals();
/* clean up */
if ( !verts ) free(verts);
if ( !norms ) free(norms);
if ( !tangents ) free(tangents);
if ( !binormals ) free(binormals);
if ( !uvs ) free(uvs);
if ( !tris ) free(tris);
/* save texture */
if ( !(dds = fopen(argv[2],"w")) ) { fclose(obj); return 4; }
fwrite(&head,sizeof(ddsheader_t),1,dds);
fwrite(tex,sizeof(pixel_t),w*h,dds);
free(tex);
fclose(dds);
return 0;
}