Code:
#include <d3d9.h>
#include <stdio.h>

void export_obj(ENTITY *entity, var scale)
{
STRING* name = str_create("#256");
STRING* objname = str_create("#256");
STRING* mtlname = str_create("#256");
str_for_entfile(name, entity);
str_trunc(name, 4);
str_lwr(name);
str_cpy(objname, name);
str_cpy(mtlname, name);
str_cat(objname, ".obj");
str_cat(mtlname, ".mtl");

int numskins = ent_skins(entity);
int i;

FILE *file = fopen(mtlname->chars, "w");

for(i = 0; i < numskins; i++)
{
fprintf(file, "newmtl material%d\n", i);
BMAP *b = bmap_for_entity(entity, i + 1);
if(b)
{
char s[80];
sprintf(s, "%s%d.bmp", name->chars, i);
bmap_save(b, s);
fprintf(file, "map_Kd %s\n", s);
}
fprintf(file, "\n");
}

fclose(file);



LPD3DXMESH mesh = (LPD3DXMESH)ent_getmesh(entity, 0, 0);
int numvertices = mesh->GetNumVertices();
int numfaces = mesh->GetNumFaces();

FILE *file = fopen(objname->chars, "w");

fprintf(file, "mtllib %s\n", mtlname->chars);
fprintf(file, "o %s\n", name->chars);

D3DVERTEX *vb; mesh->LockVertexBuffer(0, (void**)&vb);
WORD *ib; mesh->LockIndexBuffer(0, (void**)&ib);
DWORD *ab; mesh->LockAttributeBuffer(0, &ab);

for(i = 0; i < numvertices; i++)
fprintf(file, "v %f %f %f\n",
-(double)(vb[i].x * scale), (double)(vb[i].y * scale), (double)(vb[i].z * scale));

for(i = 0; i < numvertices; i++)
fprintf(file, "vt %f %f\n", (double)vb[i].u1, 1 - (double)vb[i].v1);

for(i = 0; i < numvertices; i++)
fprintf(file, "vn %f %f %f\n", -(double)vb[i].nx, (double)vb[i].ny, (double)vb[i].nz);

fprintf(file, "s on\n");

int material, a, b, c;
int previousmaterial = -999;
for(i = 0; i < numfaces; i++)
{
material = ab[i];
if(material != previousmaterial)
fprintf(file, "usemtl material%d\n", material);
previousmaterial = material;

a = ib[i*3+2] + 1;
b = ib[i*3+1] + 1;
c = ib[i*3+0] + 1;
fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", a, a, a, b, b, b, c, c, c);
}

mesh->UnlockVertexBuffer();
mesh->UnlockIndexBuffer();
mesh->UnlockAttributeBuffer();

fclose(file);

str_remove(name);
str_remove(objname);
str_remove(mtlname);
}



a simple obj exporter. it writes out the mesh buffers directly so there will be hard edges at uv-borders if your modeling application recalculates the normals. the exporter could solve this by building an optimized mesh (and by supporting smoothing groups) but it would be a lot more work. in your modeling application you just would have to weld the split vertices at those borders anyway.