// objTriangleLists produces a map of strings that can be used to write the // triangle lists for all frames of an MD3's surface. Special variation on the // forAllSurfaces function that handles base vertices (i.e., sequence is // much more important). func objTriangleLists(model *md3.Model) map[*md3.Surface]string { numSurfs := model.NumSurfaces() triStrings := make(map[*md3.Surface]string, numSurfs) builtPairs := make(chan surfaceStringPair) waitSignal := make(chan bool) baseVertex := 1 for surfaceIndex := 0; surfaceIndex < numSurfs; surfaceIndex++ { surf := model.Surface(surfaceIndex) go surfaceTriangleList(surf, baseVertex, builtPairs) baseVertex += surf.NumVertices() } go func(count int, builtPairs <-chan surfaceStringPair, waitSignal chan<- bool) { for ; count > 0; count-- { pair := <-builtPairs triStrings[pair.surface] = pair.value } waitSignal <- true }(numSurfs, builtPairs, waitSignal) <-waitSignal return triStrings }
func performConvertModel(modelPath string, model *md3.Model, signal chan<- bool, writeQueue chan<- func()) { waitSignal := make(chan bool) triLists := objTriangleLists(model) tcLists := objTexCoordLists(model) var _ = triLists var _ = tcLists name := path.Base(modelPath) name = name[:len(name)-len(path.Ext(name))] dir := path.Clean(*outputPath) os.MkdirAll(dir, 0755) numFrames := model.NumFrames() for frame := 0; frame < numFrames; frame++ { go func(frame int) { writeQueue <- func() { defer func(waitSignal chan<- bool) { go func() { waitSignal <- true }() }(waitSignal) var err error var file *os.File outName := fmt.Sprintf("%s+%d.obj", name, frame) outPath := path.Join(dir, outName) file, err = os.Create(outPath) if err != nil { log.Println("Error creating", outPath, "from", modelPath, "->", err) return } defer file.Close() _, err = fmt.Fprintf(file, "o %s\n", model.Name()) if err != nil { log.Println("Error writing header for", outPath, "from", modelPath, "->", err) } numSurfaces := model.NumSurfaces() posNorms := objPosNormLists(model, frame) for surfIndex := 0; surfIndex < numSurfaces; surfIndex++ { surf := model.Surface(surfIndex) err = writeOBJSurface(file, surf, posNorms, tcLists, triLists) if err != nil { log.Println("Error writing surface for", outPath, "from", modelPath, "->", err) return } } } }(frame) } for frame := 0; frame < numFrames; frame++ { <-waitSignal } signal <- true }
// forAllSurfaces loops over all surfaces of the given model and concurrently // launches functions mapping the surfaces to string values. The results of the // mapping operation are handled by a single goroutine to prevent writes from // potentially parallel sources. func forAllSurfaces(model *md3.Model, fn surfaceMappingFunc) map[*md3.Surface]string { numSurfs := model.NumSurfaces() pairs := make(map[*md3.Surface]string, numSurfs) builtPairs := make(chan surfaceStringPair) waitSignal := make(chan bool) for surfaceIndex := 0; surfaceIndex < numSurfs; surfaceIndex++ { surf := model.Surface(surfaceIndex) go fn(surf, builtPairs) } go func(count int, builtPairs <-chan surfaceStringPair, waitSignal chan<- bool) { for ; count > 0; count-- { pair := <-builtPairs pairs[pair.surface] = pair.value } waitSignal <- true }(numSurfs, builtPairs, waitSignal) <-waitSignal return pairs }