Teste: Usando STL para ler modelos Wavefront

No meu artigo no Projeto Virtual Worlds sobre leitura de modelos no formato Wavefront (aqui) usei as funções de streaming da biblioteca padrão de C. Aqui vai uma ligeira modificação, usando a STL, de C++:

#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <sstream>
#include <fstream>

struct vec3 { float x, y, z; }
struct indexes { int v, n; }

int readObj(const char *filename)
{
  std::ifstream f(filename);

  if (!f.is_open())
  {
    fprintf(stderr, "Unable to open file.\n");
    exit(EXIT_FAILURE);
  }

  vec3 v;
  indexes i;

  std::string line;
  std::vector<vec3>    vertices;
  std::vector<vec3>    normals;
  std::vector<indexes> idxs;
  
  while (!getline(f, line).eof())
  {
    std::stringstream sstrm(line);
    std::string token;

    sstrm >> token;
    
    /* Não me preocupei com texturas aqui. */
    if (token == "v")
    {
      sstrm >> v.x;
      sstrm >> v.y;
      sstrm >> v.z;
      vertices.push_back(v);  
    }
    else if (token == "vn")
    {
      sstrm >> v.x;
      sstrm >> v.y;
      sstrm >> v.z;
      normals.push_back(v);  
    }
    else if (token == "f")
    {
      /* NOTA: Como os índices começam com 1, no arquivo OBJ, então
               decremento antes de colocar na lista. */
      std::string value;

      sstrm >> value; 
      sscanf(value.c_str(), "%d//%d", &i.v, &i.n);  
      i.v--; i.n--;
      idxs.push_back(i);

      sstrm >> value; 
      sscanf(value.c_str(), "%d//%d", &i.v, &i.n); 
      i.v--; i.n--;
      idxs.push_back(i);

      sstrm >> value; 
      sscanf(value.c_str(), "%d//%d", &i.v, &i.n); 
      i.v--; i.n--;
      idxs.push_back(i);
    }
  }

  f.close();

  /* Usando display lists pq o teste foi feito com
     OpenGL 1.4 (vertex buffers existem no 1.5+). 

     Poderíamos usar o mesmo loop abaixo para monstar um
     vertex buffer object. */
  int displayList = glGenLists(1);
  
  if (displayList)
  {
    glNewList(displayList, GL_COMPILE);
      glBegin( GL_TRIANGLES );
  
      std::vector<indexes>::iterator nIdx;
  
      for (nIdx = idxs.begin(); nIdx != idxs.end(); ++nIdx)
      {
        v = normals[nIdx->n];
        glNormal3fv( (float *)&v );
  
        v = vertices[nIdx->v];
        glVertex3fv( (float *)&v );
      }
  
      glEnd();
    glEndList();
  }
  
  return displayList;

  /* NOTA: Todos os vetores serão limpos aqui... */
}

A rotina é essencialmente a mesma do artigo original, só uso a classe stringstream para separar as substrings automaticamente e para realizar as conversões para float… O uso da classe ifstream também facilita a vida, mas não é tão diferente assim do que usar fopen e fclose.

Outra vantagem é que as strings são alocadas sem a interferência do programador. A STL faz isso de uma maneira performática… A liberação de recursos também é “automática” assim que os objetos saem do escopo…

A desvantagem, é claro, é que o código final fica um pouco balofo. Mas, só um pouquinho…

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s