1//
2// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "shader_utils.h"
8
9#include <vector>
10#include <iostream>
11#include <fstream>
12
13static std::string ReadFileToString(const std::string &source)
14{
15    std::ifstream stream(source);
16    if (!stream)
17    {
18        std::cerr << "Failed to load shader file: " << source;
19        return "";
20    }
21
22    std::string result;
23
24    stream.seekg(0, std::ios::end);
25    result.reserve(stream.tellg());
26    stream.seekg(0, std::ios::beg);
27
28    result.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
29
30    return result;
31}
32
33GLuint CompileShader(GLenum type, const std::string &source)
34{
35    GLuint shader = glCreateShader(type);
36
37    const char *sourceArray[1] = { source.c_str() };
38    glShaderSource(shader, 1, sourceArray, NULL);
39    glCompileShader(shader);
40
41    GLint compileResult;
42    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
43
44    if (compileResult == 0)
45    {
46        GLint infoLogLength;
47        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
48
49        std::vector<GLchar> infoLog(infoLogLength);
50        glGetShaderInfoLog(shader, infoLog.size(), NULL, infoLog.data());
51
52        std::cerr << "shader compilation failed: " << infoLog.data();
53
54        glDeleteShader(shader);
55        shader = 0;
56    }
57
58    return shader;
59}
60
61GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
62{
63    std::string source = ReadFileToString(sourcePath);
64    if (source.empty())
65    {
66        return 0;
67    }
68
69    return CompileShader(type, source);
70}
71
72GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
73{
74    GLuint program = glCreateProgram();
75
76    GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
77    GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
78
79    if (vs == 0 || fs == 0)
80    {
81        glDeleteShader(fs);
82        glDeleteShader(vs);
83        glDeleteProgram(program);
84        return 0;
85    }
86
87    glAttachShader(program, vs);
88    glDeleteShader(vs);
89
90    glAttachShader(program, fs);
91    glDeleteShader(fs);
92
93    glLinkProgram(program);
94
95    GLint linkStatus;
96    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
97
98    if (linkStatus == 0)
99    {
100        GLint infoLogLength;
101        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
102
103        std::vector<GLchar> infoLog(infoLogLength);
104        glGetProgramInfoLog(program, infoLog.size(), NULL, infoLog.data());
105
106        std::cerr << "program link failed: " << infoLog.data();
107
108        glDeleteProgram(program);
109        return 0;
110    }
111
112    return program;
113}
114
115GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
116{
117    std::string vsSource = ReadFileToString(vsPath);
118    std::string fsSource = ReadFileToString(fsPath);
119    if (vsSource.empty() || fsSource.empty())
120    {
121        return 0;
122    }
123
124    return CompileProgram(vsSource, fsSource);
125}
126