Пример #1
0
Ref<Material> Material::read(RenderContext& context, const std::string& name)
{
  initializeMaps();

  if (Material* cached = context.cache().find<Material>(name))
    return cached;

  const Path path = context.cache().findFile(name);
  if (path.isEmpty())
  {
    logError("Failed to find material %s", name.c_str());
    return nullptr;
  }

  pugi::xml_document document;

  const pugi::xml_parse_result result = document.load_file(path.name().c_str());
  if (!result)
  {
    logError("Failed to load material %s: %s",
             name.c_str(),
             result.description());
    return nullptr;
  }

  pugi::xml_node root = document.child("material");
  if (!root || root.attribute("version").as_uint() != MATERIAL_XML_VERSION)
  {
    logError("Material file format mismatch in %s", name.c_str());
    return nullptr;
  }

  Ref<Material> material = Material::create(ResourceInfo(context.cache(), name, path), context);

  for (auto pn : root.children("pass"))
  {
    const std::string phaseName(pn.attribute("phase").value());
    if (!phaseMap.hasKey(phaseName))
    {
      logError("Invalid render phase %s in material %s",
               phaseName.c_str(),
               name.c_str());
      return nullptr;
    }

    if (!parsePass(context, material->pass(phaseMap[phaseName]), pn))
    {
      logError("Failed to parse pass for material %s", name.c_str());
      return nullptr;
    }
  }

  return material;
}
Пример #2
0
Ref<Font> Font::read(RenderContext& context, const std::string& name)
{
  if (Font* cached = context.cache().find<Font>(name))
    return cached;

  const Path path = context.cache().findFile(name);
  if (path.isEmpty())
  {
    logError("Failed to find font %s", name.c_str());
    return nullptr;
  }

  pugi::xml_document document;

  const pugi::xml_parse_result result = document.load_file(path.name().c_str());
  if (!result)
  {
    logError("Failed to load font %s: %s",
             name.c_str(),
             result.description());
    return nullptr;
  }

  pugi::xml_node root = document.child("font");
  if (!root || root.attribute("version").as_uint() != FONT_XML_VERSION)
  {
    logError("Font file format mismatch in %s", name.c_str());
    return nullptr;
  }

  const std::string faceName(root.attribute("face").value());
  if (faceName.empty())
  {
    logError("No typeface specified for font %s", faceName.c_str());
    return nullptr;
  }

  const uint height = root.attribute("height").as_uint();

  Ref<Face> face = Face::read(context.cache(), faceName);
  if (!face)
    return nullptr;

  return create(ResourceInfo(context.cache(), name, path),
                context, *face, height);
}
Пример #3
0
bool parsePass(RenderContext& context, Pass& pass, pugi::xml_node root)
{
  initializeMaps();

  ResourceCache& cache = context.cache();

  if (pugi::xml_node node = root.child("blending"))
  {
    if (pugi::xml_attribute a = node.attribute("src"))
    {
      if (blendFactorMap.hasKey(a.value()))
        pass.setBlendFactors(blendFactorMap[a.value()], pass.dstFactor());
      else
      {
        logError("Invalid source blend factor %s", a.value());
        return false;
      }
    }

    if (pugi::xml_attribute a = node.attribute("dst"))
    {
      if (blendFactorMap.hasKey(a.value()))
        pass.setBlendFactors(pass.srcFactor(), blendFactorMap[a.value()]);
      else
      {
        logError("Invalid destination blend factor %s", a.value());
        return false;
      }
    }
  }

  if (pugi::xml_node node = root.child("color"))
  {
    if (pugi::xml_attribute a = node.attribute("writing"))
      pass.setColorWriting(a.as_bool());

    if (pugi::xml_attribute a = node.attribute("multisampling"))
      pass.setMultisampling(a.as_bool());
  }

  if (pugi::xml_node node = root.child("depth"))
  {
    if (pugi::xml_attribute a = node.attribute("testing"))
      pass.setDepthTesting(a.as_bool());

    if (pugi::xml_attribute a = node.attribute("writing"))
      pass.setDepthWriting(a.as_bool());

    if (pugi::xml_attribute a = node.attribute("function"))
    {
      if (functionMap.hasKey(a.value()))
        pass.setDepthFunction(functionMap[a.value()]);
      else
      {
        logError("Invalid depth function %s", a.value());
        return false;
      }
    }
  }

  if (pugi::xml_node node = root.child("stencil"))
  {
    if (pugi::xml_attribute a = node.attribute("testing"))
      pass.setStencilTesting(a.as_bool());

    for (pugi::xml_node child : node.children())
    {
      const PolygonFace face = polygonFaceMap[child.name()];
      if (face == FACE_NONE)
        continue;

      if (pugi::xml_attribute a = node.attribute("mask"))
        pass.setStencilWriteMask(face, a.as_uint());

      if (pugi::xml_attribute a = node.attribute("reference"))
        pass.setStencilReference(face, a.as_uint());

      if (pugi::xml_attribute a = node.attribute("stencilFail"))
      {
        if (functionMap.hasKey(a.value()))
          pass.setStencilFailOperation(face, operationMap[a.value()]);
        else
        {
          logError("Invalid stencil fail operation %s", a.value());
          return false;
        }
      }

      if (pugi::xml_attribute a = node.attribute("depthFail"))
      {
        if (functionMap.hasKey(a.value()))
          pass.setDepthFailOperation(face, operationMap[a.value()]);
        else
        {
          logError("Invalid depth fail operation %s", a.value());
          return false;
        }
      }

      if (pugi::xml_attribute a = node.attribute("depthPass"))
      {
        if (functionMap.hasKey(a.value()))
          pass.setDepthPassOperation(face, operationMap[a.value()]);
        else
        {
          logError("Invalid depth pass operation %s", a.value());
          return false;
        }
      }

      if (pugi::xml_attribute a = node.attribute("function"))
      {
        if (functionMap.hasKey(a.value()))
          pass.setStencilFunction(face, functionMap[a.value()]);
        else
        {
          logError("Invalid stencil function %s", a.value());
          return false;
        }
      }
    }
  }

  if (pugi::xml_node node = root.child("polygon"))
  {
    if (pugi::xml_attribute a = node.attribute("wireframe"))
      pass.setWireframe(a.as_bool());

    if (pugi::xml_attribute a = node.attribute("cull"))
    {
      if (polygonFaceMap.hasKey(a.value()))
        pass.setCullFace(polygonFaceMap[a.value()]);
      else
      {
        logError("Invalid cull face %s", a.value());
        return false;
      }
    }
  }

  if (pugi::xml_node node = root.child("line"))
  {
    if (pugi::xml_attribute a = node.attribute("smoothing"))
      pass.setLineSmoothing(a.as_bool());

    if (pugi::xml_attribute a = node.attribute("width"))
      pass.setLineWidth(a.as_float());
  }

  if (pugi::xml_node node = root.child("program"))
  {
    const std::string vertexShaderName(node.attribute("vs").value());
    if (vertexShaderName.empty())
    {
      logError("No vertex shader specified");
      return false;
    }

    const std::string fragmentShaderName(node.attribute("fs").value());
    if (fragmentShaderName.empty())
    {
      logError("No fragment shader specified");
      return false;
    }

    Ref<Program> program = Program::read(context,
                                         vertexShaderName,
                                         fragmentShaderName);
    if (!program)
    {
      logError("Failed to load program");
      return false;
    }

    pass.setProgram(program);

    for (auto u : node.children("uniform"))
    {
      const std::string uniformName(u.attribute("name").value());
      if (uniformName.empty())
      {
        logWarning("Program %s lists unnamed uniform",
                   program->name().c_str());

        continue;
      }

      const Uniform* uniform = program->findUniform(uniformName.c_str());
      if (!uniform)
      {
        logWarning("Program %s does not have uniform %s",
                   program->name().c_str(),
                   uniformName.c_str());

        continue;
      }

      if (uniform->isSampler())
      {
        Ref<Texture> texture;

        if (pugi::xml_attribute a = u.attribute("image"))
        {
          TextureParams params(TextureType(uniform->type()), TF_NONE);

          if (u.attribute("mipmapped").as_bool())
            params.flags |= TF_MIPMAPPED;

          if (u.attribute("sRGB").as_bool())
            params.flags |= TF_SRGB;

          if (pugi::xml_attribute a = u.attribute("filter"))
          {
            if (filterModeMap.hasKey(a.value()))
              params.filterMode = filterModeMap[a.value()];
            else
            {
              logError("Invalid filter mode name %s", a.value());
              return false;
            }
          }

          if (pugi::xml_attribute a = u.attribute("address"))
          {
            if (addressModeMap.hasKey(a.value()))
              params.addressMode = addressModeMap[a.value()];
            else
            {
              logError("Invalid address mode name %s", a.value());
              return false;
            }
          }

          if (pugi::xml_attribute a = u.attribute("anisotropy"))
            params.maxAnisotropy = a.as_float();

          texture = Texture::read(context, params, a.value());
        }
        else if (pugi::xml_attribute a = u.attribute("texture"))
          texture = cache.find<Texture>(a.value());
        else
        {
          logError("No texture specified for uniform %s of program %s",
                   uniformName.c_str(),
                   program->name().c_str());

          return false;
        }

        if (!texture)
        {
          logError("Failed to find texture for uniform %s of program %s",
                   uniformName.c_str(),
                   program->name().c_str());

          return false;
        }

        pass.setUniformTexture(uniformName.c_str(), texture);
      }
      else
      {
        pugi::xml_attribute attribute = u.attribute("value");
        if (!attribute)
        {
          logError("Missing value for uniform %s of program %s",
                   uniformName.c_str(),
                   program->name().c_str());

          return false;
        }

        switch (uniform->type())
        {
          case UNIFORM_INT:
            pass.setUniformState(uniformName.c_str(), attribute.as_int());
            break;
          case UNIFORM_UINT:
            pass.setUniformState(uniformName.c_str(), attribute.as_uint());
            break;
          case UNIFORM_FLOAT:
            pass.setUniformState(uniformName.c_str(), attribute.as_float());
            break;
          case UNIFORM_VEC2:
            pass.setUniformState(uniformName.c_str(), vec2Cast(attribute.value()));
            break;
          case UNIFORM_VEC3:
            pass.setUniformState(uniformName.c_str(), vec3Cast(attribute.value()));
            break;
          case UNIFORM_VEC4:
            pass.setUniformState(uniformName.c_str(), vec4Cast(attribute.value()));
            break;
          case UNIFORM_MAT2:
            pass.setUniformState(uniformName.c_str(), mat2Cast(attribute.value()));
            break;
          case UNIFORM_MAT3:
            pass.setUniformState(uniformName.c_str(), mat3Cast(attribute.value()));
            break;
          case UNIFORM_MAT4:
            pass.setUniformState(uniformName.c_str(), mat4Cast(attribute.value()));
            break;
        }
      }
    }
  }

  return true;
}