You have the right concept.
Here's AC3D's internal code that calculates the normals.
Code:
// get the crease angle in radians
float rad_angle = cos(ob->crease_angle * M_PI / 180.0f);
...
{
// vertex index will hold a list of each surface that references the vertex
// first, clear the lists
for (List *p = ob->pointlist; p != NULL; p = p->next)
{
Vertex *v = (Vertex *)p->data;
vertex_set_index(v, NULL);
}
// for each sv, add the surface to the list of surfaces in each vertex
for (List *spp = ob->surfacelist; spp != NULL; spp = spp->next)
{
Surface *s = (Surface *)spp->data;
for (List *svp = s->vertlist; svp != NULL; svp = svp->next)
{
SVertex *sv = (SVertex *)svp->data;
list_add_item_head((List **)&(sv->v->index), s);
}
}
for (List *sp = ob->surfacelist; sp != NULL; sp = sp->next)
{
Surface *s = (Surface *)sp->data;
for (List *svp = s->vertlist; svp != NULL; svp = svp->next)
{
SVertex *sv = (SVertex *)svp->data;
sv->normal = s->normal;
if ((vertex_get_index(sv->v) == 0))
{
continue; // next please
}
// so, surface is shaded
// fl is list of faces that refer to this vertex
List *fl = (List *)vertex_get_index(sv->v);
for (List *flp = fl; flp != NULL; flp = flp->next)
{
Surface *os = (Surface *)flp->data;
// ignore if the same surface
if (s != os)
{
// even if the surface is flat, we still calculate the normals
// the shading may change and this saves recalulating normals again
// calc dot product of this surface plus attached
float dot = (DOTPRODUCT(&s->normal, &os->normal));
if (dot > rad_angle)
{
ADDPOINTS(&os->normal, &sv->normal);
}
}
}
normalize_point(&sv->normal);
}
}
for (List *vp = ob->pointlist; vp != NULL; vp = vp->next)
{
Vertex *v = (Vertex *)vp->data;
list_free((List **)&vertex_get_index(v));
}
}
Notes:
1) that the vertex_index stuff is internal and you'll need to use another way of storing the vertex info.
2) The surface flag for shading is used when drawing the model - if a surface is 'smooth', the vertex normals are used. If a surface is 'flat', the surface-normal is used for each vertex.
3) the above code calculates the all normals in an object (not just those changed recently). Some bits of internal code have been removed but I've hopefully left the important stuff. If the crease angle is 0 or 180, you can optimize a bit.