Support macOS + OpenGL 3.3+ GPU

This commit is contained in:
Syoyo Fujita 2019-01-14 22:10:32 +09:00
parent d6b0b0b990
commit b864ea7349
4 changed files with 244 additions and 246 deletions

View File

@ -2,10 +2,12 @@
## Requirements ## Requirements
* glew
* glfw3 * glfw3
* premake5(linux) * premake5(linux)
* OpenGL 3.3+ GPU
## Build on Linux ## Build on Linux and macOS
``` ```
$ premake5 gmake $ premake5 gmake

View File

@ -1,12 +1,12 @@
#include <iostream> #include <fstream>
#include <fstream> #include <iostream>
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include "window.h"
#include "shaders.h" #include "shaders.h"
#include "window.h"
#define TINYGLTF_IMPLEMENTATION #define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
@ -17,9 +17,7 @@
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) #define BUFFER_OFFSET(i) ((char *)NULL + (i))
bool loadModel(tinygltf::Model &model, const char *filename) {
bool loadModel(tinygltf::Model &model, const char* filename)
{
tinygltf::TinyGLTF loader; tinygltf::TinyGLTF loader;
std::string err; std::string err;
std::string warn; std::string warn;
@ -35,24 +33,25 @@ bool loadModel(tinygltf::Model &model, const char* filename)
if (!res) if (!res)
std::cout << "Failed to load glTF: " << filename << std::endl; std::cout << "Failed to load glTF: " << filename << std::endl;
else std::cout << "Loaded glTF: " << filename << std::endl; else
std::cout << "Loaded glTF: " << filename << std::endl;
return res; return res;
} }
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos, tinygltf::Model &model, tinygltf::Mesh &mesh) tinygltf::Model &model, tinygltf::Mesh &mesh) {
{
for (size_t i = 0; i < model.bufferViews.size(); ++i) { for (size_t i = 0; i < model.bufferViews.size(); ++i) {
const tinygltf::BufferView &bufferView = model.bufferViews[i]; const tinygltf::BufferView &bufferView = model.bufferViews[i];
if (bufferView.target == 0) { // TODO impl drawarrays if (bufferView.target == 0) { // TODO impl drawarrays
std::cout << "WARN: bufferView.target is zero" << std::endl; std::cout << "WARN: bufferView.target is zero" << std::endl;
continue; // Unsupported bufferView. continue; // Unsupported bufferView.
/* /*
From spec2.0 readme: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0 From spec2.0 readme:
... drawArrays function should be used with a count equal to the count https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
property of any of the accessors referenced by the attributes property ... drawArrays function should be used with a count equal to
(they are all equal for a given primitive). the count property of any of the accessors referenced by the attributes
property (they are all equal for a given primitive).
*/ */
} }
@ -64,22 +63,22 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos, tinygltf::Model &mode
vbos[i] = vbo; vbos[i] = vbo;
glBindBuffer(bufferView.target, vbo); glBindBuffer(bufferView.target, vbo);
std::cout << "buffer.data.size = " << buffer.data.size() << ", bufferview.byteOffset = " std::cout << "buffer.data.size = " << buffer.data.size()
<< bufferView.byteOffset << std::endl; << ", bufferview.byteOffset = " << bufferView.byteOffset
<< std::endl;
glBufferData(bufferView.target, bufferView.byteLength, glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
} }
for (size_t i = 0; i < mesh.primitives.size(); ++i) for (size_t i = 0; i < mesh.primitives.size(); ++i) {
{
tinygltf::Primitive primitive = mesh.primitives[i]; tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
for (auto& attrib : primitive.attributes) for (auto &attrib : primitive.attributes) {
{
tinygltf::Accessor accessor = model.accessors[attrib.second]; tinygltf::Accessor accessor = model.accessors[attrib.second];
int byteStride = accessor.ByteStride(model.bufferViews[accessor.bufferView]); int byteStride =
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]); glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
int size = 1; int size = 1;
@ -91,19 +90,13 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos, tinygltf::Model &mode
if (attrib.first.compare("POSITION") == 0) vaa = 0; if (attrib.first.compare("POSITION") == 0) vaa = 0;
if (attrib.first.compare("NORMAL") == 0) vaa = 1; if (attrib.first.compare("NORMAL") == 0) vaa = 1;
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2; if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
if (vaa > -1) if (vaa > -1) {
{
glEnableVertexAttribArray(vaa); glEnableVertexAttribArray(vaa);
glVertexAttribPointer( glVertexAttribPointer(vaa, size, accessor.componentType,
vaa,
size,
accessor.componentType,
accessor.normalized ? GL_TRUE : GL_FALSE, accessor.normalized ? GL_TRUE : GL_FALSE,
byteStride, byteStride, BUFFER_OFFSET(accessor.byteOffset));
BUFFER_OFFSET(accessor.byteOffset) } else
); std::cout << "vaa missing: " << attrib.first << std::endl;
}
else std::cout << "vaa missing: " << attrib.first << std::endl;
} }
GLuint texid; GLuint texid;
@ -119,17 +112,16 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos, tinygltf::Model &mode
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA, GL_UNSIGNED_BYTE, &image.image.at(0));
&image.image.at(0));
} }
return vbos; return vbos;
} }
// bind models // bind models
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model, tinygltf::Node &node) void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
{ tinygltf::Node &node) {
bindMesh(vbos, model, model.meshes[node.mesh]); bindMesh(vbos, model, model.meshes[node.mesh]);
for (size_t i = 0; i < node.children.size(); i++) { for (size_t i = 0; i < node.children.size(); i++) {
bindModelNodes(vbos, model, model.nodes[node.children[i]]); bindModelNodes(vbos, model, model.nodes[node.children[i]]);
@ -148,38 +140,32 @@ GLuint bindModel(tinygltf::Model &model) {
glBindVertexArray(0); glBindVertexArray(0);
// cleanup vbos // cleanup vbos
for (size_t i = 0; i < vbos.size(); ++i) for (size_t i = 0; i < vbos.size(); ++i) {
{
glDeleteBuffers(1, &vbos[i]); glDeleteBuffers(1, &vbos[i]);
} }
return vao; return vao;
} }
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh)
{
for (size_t i = 0; i < mesh.primitives.size(); ++i)
{
tinygltf::Primitive primitive = mesh.primitives[i]; tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
glDrawElements(primitive.mode, indexAccessor.count, indexAccessor.componentType, glDrawElements(primitive.mode, indexAccessor.count,
indexAccessor.componentType,
BUFFER_OFFSET(indexAccessor.byteOffset)); BUFFER_OFFSET(indexAccessor.byteOffset));
} }
} }
// recursively draw node and children nodes of model // recursively draw node and children nodes of model
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
{
drawMesh(model, model.meshes[node.mesh]); drawMesh(model, model.meshes[node.mesh]);
for (size_t i = 0; i < node.children.size(); i++) { for (size_t i = 0; i < node.children.size(); i++) {
drawModelNodes(model, model.nodes[node.children[i]]); drawModelNodes(model, model.nodes[node.children[i]]);
} }
} }
void drawModel(GLuint vao, tinygltf::Model &model) void drawModel(GLuint vao, tinygltf::Model &model) {
{
glBindVertexArray(vao); glBindVertexArray(vao);
const tinygltf::Scene &scene = model.scenes[model.defaultScene]; const tinygltf::Scene &scene = model.scenes[model.defaultScene];
@ -190,48 +176,40 @@ void drawModel(GLuint vao, tinygltf::Model &model)
glBindVertexArray(0); glBindVertexArray(0);
} }
void dbgModel(tinygltf::Model &model) {
for (auto &mesh : model.meshes) {
void dbgModel(tinygltf::Model &model)
{
for (auto &mesh : model.meshes)
{
std::cout << "mesh : " << mesh.name << std::endl; std::cout << "mesh : " << mesh.name << std::endl;
for (auto &primitive : mesh.primitives) for (auto &primitive : mesh.primitives) {
{ const tinygltf::Accessor &indexAccessor =
const tinygltf::Accessor &indexAccessor = model.accessors[primitive.indices]; model.accessors[primitive.indices];
std::cout << "indexaccessor: count " << indexAccessor.count << ", type " << std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
indexAccessor.componentType << std::endl; << indexAccessor.componentType << std::endl;
tinygltf::Material &mat = model.materials[primitive.material]; tinygltf::Material &mat = model.materials[primitive.material];
for (auto &mats : mat.values) for (auto &mats : mat.values) {
{
std::cout << "mat : " << mats.first.c_str() << std::endl; std::cout << "mat : " << mats.first.c_str() << std::endl;
} }
for (auto &image : model.images) for (auto &image : model.images) {
{
std::cout << "image name : " << image.uri << std::endl; std::cout << "image name : " << image.uri << std::endl;
std::cout << " size : " << image.image.size() << std::endl; std::cout << " size : " << image.image.size() << std::endl;
std::cout << " w/h : " << image.width << "/" << image.height << std::endl; std::cout << " w/h : " << image.width << "/" << image.height
<< std::endl;
} }
std::cout << "indices : " << primitive.indices << std::endl; std::cout << "indices : " << primitive.indices << std::endl;
std::cout << "mode : " << "(" << primitive.mode << ")" << std::endl; std::cout << "mode : "
<< "(" << primitive.mode << ")" << std::endl;
for (auto &attrib : primitive.attributes) for (auto &attrib : primitive.attributes) {
{
std::cout << "attribute : " << attrib.first.c_str() << std::endl; std::cout << "attribute : " << attrib.first.c_str() << std::endl;
} }
} }
} }
} }
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat)
{
// Camera matrix // Camera matrix
glm::mat4 view = glm::lookAt( glm::mat4 view = glm::lookAt(
pos, // Camera in World Space pos, // Camera in World Space
@ -242,21 +220,21 @@ glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat)
return view; return view;
} }
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w, int h) glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
{ int h) {
glm::mat4 Projection = glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f); glm::mat4 Projection =
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
// Or, for an ortho camera : // Or, for an ortho camera :
//glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); // In world coordinates // glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
// // In world coordinates
glm::mat4 mvp = Projection * view_mat * model_mat; glm::mat4 mvp = Projection * view_mat * model_mat;
return mvp; return mvp;
} }
void displayLoop(Window& window, const std::string &filename) void displayLoop(Window &window, const std::string &filename) {
{
Shaders shader = Shaders(); Shaders shader = Shaders();
glUseProgram(shader.pid); glUseProgram(shader.pid);
@ -269,7 +247,7 @@ void displayLoop(Window& window, const std::string &filename)
if (!loadModel(model, filename.c_str())) return; if (!loadModel(model, filename.c_str())) return;
GLuint vao = bindModel(model); GLuint vao = bindModel(model);
//dbgModel(model); return; // dbgModel(model); return;
// Model matrix : an identity matrix (model will be at the origin) // Model matrix : an identity matrix (model will be at the origin)
glm::mat4 model_mat = glm::mat4(1.0f); glm::mat4 model_mat = glm::mat4(1.0f);
@ -277,22 +255,22 @@ void displayLoop(Window& window, const std::string &filename)
glm::vec3 model_pos = glm::vec3(-3, 0, -3); glm::vec3 model_pos = glm::vec3(-3, 0, -3);
// generate a camera view, based on eye-position and lookAt world-position // generate a camera view, based on eye-position and lookAt world-position
glm::mat4 view_mat = genView(glm::vec3(2,2,2), model_pos); glm::mat4 view_mat = genView(glm::vec3(2, 2, 2), model_pos);
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0); glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
glm::vec3 sun_color = glm::vec3(1.0); glm::vec3 sun_color = glm::vec3(1.0);
while (!window.Close()) while (!window.Close()) {
{
window.Resize(); window.Resize();
glClearColor(0.2, 0.2, 0.2, 1.0); glClearColor(0.2, 0.2, 0.2, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 trans =
glm::mat4 trans = glm::translate(glm::mat4(1.0f), model_pos); // reposition model glm::translate(glm::mat4(1.0f), model_pos); // reposition model
model_rot = glm::rotate(model_rot, glm::radians(0.8f), glm::vec3(0,1,0)); // rotate model on y axis model_rot = glm::rotate(model_rot, glm::radians(0.8f),
model_mat = trans*model_rot; glm::vec3(0, 1, 0)); // rotate model on y axis
model_mat = trans * model_rot;
// build a model-view-projection // build a model-view-projection
GLint w, h; GLint w, h;
@ -309,9 +287,7 @@ void displayLoop(Window& window, const std::string &filename)
} }
} }
int main(int argc, char **argv) {
int main(int argc, char **argv)
{
std::string filename = "../../models/Cube/Cube.gltf"; std::string filename = "../../models/Cube/Cube.gltf";
if (argc > 1) { if (argc > 1) {
@ -319,11 +295,31 @@ int main(int argc, char **argv)
} }
if (!glfwInit()) return -1; if (!glfwInit()) return -1;
// Force create 3.3 profile.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
Window window = Window(800, 600, "TinyGLTF basic example"); Window window = Window(800, 600, "TinyGLTF basic example");
glfwMakeContextCurrent(window.window); glfwMakeContextCurrent(window.window);
#ifdef __APPLE__
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
glewExperimental = GL_TRUE;
#endif
glewInit(); glewInit();
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION) << std::endl; std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
<< std::endl;
if (!GLEW_VERSION_3_3) {
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
return EXIT_FAILURE;
}
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS); glDepthFunc(GL_LESS);

View File

@ -30,7 +30,7 @@ solution "basic_viewer"
includedirs { "/usr/local/include" } includedirs { "/usr/local/include" }
buildoptions { "-Wno-deprecated-declarations" } buildoptions { "-Wno-deprecated-declarations" }
libdirs { "/usr/local/lib" } libdirs { "/usr/local/lib" }
links { "glfw3", "GLEW" } links { "glfw", "GLEW" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" } linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
configuration "Debug" configuration "Debug"

View File

@ -19,7 +19,7 @@ uniform vec3 sun_color; \n\
out vec4 color;\n\ out vec4 color;\n\
void main() {\n\ void main() {\n\
float lum = max(dot(normal, normalize(sun_position)), 0.0);\n\ float lum = max(dot(normal, normalize(sun_position)), 0.0);\n\
color = texture2D(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\ color = texture(tex, texcoord) * vec4((0.3 + 0.7 * lum) * sun_color, 1.0);\n\
}\n\ }\n\
"; ";