#pragma once /************************************************************************************ Filename : Win32_GLAppUtil.h Content : OpenGL and Application/Window setup functionality for RoomTiny Created : October 20th, 2014 Author : Tom Heath Copyright : Copyright 2014 Oculus, LLC. All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *************************************************************************************/ // custom version 2016.9.11 by memoblog #include "GL/glew.h" #include "GL/freeglut.h" #include "Extras/OVR_Math.h" #include "OVR_CAPI_GL.h" #include "Kernel/OVR_Types.h" #include "Kernel/OVR_System.h" #include #if defined(_WIN32) #include // for GetDefaultAdapterLuid #pragma comment(lib, "dxgi.lib") #endif using namespace OVR; #ifndef VALIDATE #define VALIDATE(x, msg) if (!(x)) { MessageBoxA(NULL, (msg), "OculusRoomTiny", MB_ICONERROR | MB_OK); exit(-1); } #endif #ifndef OVR_DEBUG_LOG #define OVR_DEBUG_LOG(x) #endif //--------------------------------------------------------------------------------------- struct DepthBuffer { GLuint texId; DepthBuffer(Sizei size, int sampleCount) { UNREFERENCED_PARAMETER(sampleCount); assert(sampleCount <= 1); // The code doesn't currently handle MSAA textures. glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); GLenum internalFormat = GL_DEPTH_COMPONENT24; GLenum type = GL_UNSIGNED_INT; // if (GLE_ARB_depth_buffer_float) { internalFormat = GL_DEPTH_COMPONENT32F; type = GL_FLOAT; } glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size.w, size.h, 0, GL_DEPTH_COMPONENT, type, NULL); } ~DepthBuffer() { if (texId) { glDeleteTextures(1, &texId); texId = 0; } } }; //-------------------------------------------------------------------------- struct TextureBuffer { ovrSession Session; ovrTextureSwapChain TextureChain; GLuint texId; GLuint fboId; Sizei texSize; TextureBuffer(ovrSession session, bool rendertarget, bool displayableOnHmd, Sizei size, int mipLevels, unsigned char * data, int sampleCount) : Session(session), TextureChain(nullptr), texId(0), fboId(0), texSize(0, 0) { UNREFERENCED_PARAMETER(sampleCount); assert(sampleCount <= 1); // The code doesn't currently handle MSAA textures. texSize = size; if (displayableOnHmd) { // This texture isn't necessarily going to be a rendertarget, but it usually is. assert(session); // No HMD? A little odd. assert(sampleCount == 1); // ovr_CreateSwapTextureSetD3D11 doesn't support MSAA. ovrTextureSwapChainDesc desc = {}; desc.Type = ovrTexture_2D; desc.ArraySize = 1; desc.Width = size.w; desc.Height = size.h; desc.MipLevels = 1; desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; desc.SampleCount = 1; desc.StaticImage = ovrFalse; ovrResult result = ovr_CreateTextureSwapChainGL(Session, &desc, &TextureChain); int length = 0; ovr_GetTextureSwapChainLength(session, TextureChain, &length); if (OVR_SUCCESS(result)) { for (int i = 0; i < length; ++i) { GLuint chainTexId; ovr_GetTextureSwapChainBufferGL(Session, TextureChain, i, &chainTexId); glBindTexture(GL_TEXTURE_2D, chainTexId); if (rendertarget) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } } } } else { glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); if (rendertarget) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, texSize.w, texSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); } if (mipLevels > 1) { glGenerateMipmap(GL_TEXTURE_2D); } glGenFramebuffers(1, &fboId); } ~TextureBuffer() { if (TextureChain) { ovr_DestroyTextureSwapChain(Session, TextureChain); TextureChain = nullptr; } if (texId) { glDeleteTextures(1, &texId); texId = 0; } if (fboId) { glDeleteFramebuffers(1, &fboId); fboId = 0; } } Sizei GetSize() const { return texSize; } void SetAndClearRenderSurface(DepthBuffer* dbuffer) { GLuint curTexId; if (TextureChain) { int curIndex; ovr_GetTextureSwapChainCurrentIndex(Session, TextureChain, &curIndex); ovr_GetTextureSwapChainBufferGL(Session, TextureChain, curIndex, &curTexId); } else { curTexId = texId; } glBindFramebuffer(GL_FRAMEBUFFER, fboId); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dbuffer->texId, 0); glViewport(0, 0, texSize.w, texSize.h); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_FRAMEBUFFER_SRGB); } void UnsetRenderSurface() { glBindFramebuffer(GL_FRAMEBUFFER, fboId); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); } void Commit() { if (TextureChain) { ovr_CommitTextureSwapChain(Session, TextureChain); } } }; static ovrGraphicsLuid GetDefaultAdapterLuid() { ovrGraphicsLuid luid = ovrGraphicsLuid(); #if defined(_WIN32) IDXGIFactory* factory = nullptr; if (SUCCEEDED(CreateDXGIFactory(IID_PPV_ARGS(&factory)))) { IDXGIAdapter* adapter = nullptr; if (SUCCEEDED(factory->EnumAdapters(0, &adapter))) { DXGI_ADAPTER_DESC desc; adapter->GetDesc(&desc); memcpy(&luid, &desc.AdapterLuid, sizeof(luid)); adapter->Release(); } factory->Release(); } #endif return luid; } static int Compare(const ovrGraphicsLuid& lhs, const ovrGraphicsLuid& rhs) { return memcmp(&lhs, &rhs, sizeof(ovrGraphicsLuid)); } //------------------------------------------------------------------------------ struct ShaderFill { GLuint program; TextureBuffer * texture; ShaderFill(GLuint vertexShader, GLuint pixelShader, TextureBuffer* _texture) { texture = _texture; program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, pixelShader); glLinkProgram(program); glDetachShader(program, vertexShader); glDetachShader(program, pixelShader); GLint r; glGetProgramiv(program, GL_LINK_STATUS, &r); if (!r) { GLchar msg[1024]; glGetProgramInfoLog(program, sizeof(msg), 0, msg); } } ~ShaderFill() { if (program) { glDeleteProgram(program); program = 0; } if (texture) { delete texture; texture = nullptr; } } }; //---------------------------------------------------------------- struct VertexBuffer { GLuint buffer; VertexBuffer(void* vertices, size_t size) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW); } ~VertexBuffer() { if (buffer) { glDeleteBuffers(1, &buffer); buffer = 0; } } }; //---------------------------------------------------------------- struct IndexBuffer { GLuint buffer; IndexBuffer(void* indices, size_t size) { glGenBuffers(1, &buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW); } ~IndexBuffer() { if (buffer) { glDeleteBuffers(1, &buffer); buffer = 0; } } }; //--------------------------------------------------------------------------- struct Model { struct Vertex { Vector3f Pos; DWORD C; float U, V; }; Vector3f Pos; Quatf Rot; Matrix4f Mat; int numVertices, numIndices; Vertex * Vertices; // Note fixed maximum GLushort * Indices; ShaderFill * Fill; VertexBuffer * vertexBuffer; IndexBuffer * indexBuffer; Model(Vector3f pos, ShaderFill * fill, const int nV = 2000, const int nI = 2000) : numVertices(0), numIndices(0), Pos(pos), Rot(), Mat(), Fill(fill), vertexBuffer(nullptr), indexBuffer(nullptr) { Vertices = new Vertex[nV]; Indices = new GLushort[nI]; } ~Model() { FreeBuffers(); } Matrix4f& GetMatrix() { Mat = Matrix4f(Rot); Mat = Matrix4f::Translation(Pos) * Mat; return Mat; } void AddVertex(const Vertex& v) { Vertices[numVertices++] = v; } void AddIndex(GLushort a) { Indices[numIndices++] = a; } void AllocateBuffers() { vertexBuffer = new VertexBuffer(&Vertices[0], numVertices * sizeof(Vertices[0])); indexBuffer = new IndexBuffer(&Indices[0], numIndices * sizeof(Indices[0])); } void FreeBuffers() { delete vertexBuffer; vertexBuffer = nullptr; delete indexBuffer; indexBuffer = nullptr; delete[] Vertices; Vertices = nullptr; delete[] Indices; Indices = nullptr; } void AddSolidColorBox(float x1, float y1, float z1, float x2, float y2, float z2, DWORD c) { Vector3f Vert[][2] = { Vector3f(x1, y2, z1), Vector3f(z1, x1), Vector3f(x2, y2, z1), Vector3f(z1, x2), Vector3f(x2, y2, z2), Vector3f(z2, x2), Vector3f(x1, y2, z2), Vector3f(z2, x1), Vector3f(x1, y1, z1), Vector3f(z1, x1), Vector3f(x2, y1, z1), Vector3f(z1, x2), Vector3f(x2, y1, z2), Vector3f(z2, x2), Vector3f(x1, y1, z2), Vector3f(z2, x1), Vector3f(x1, y1, z2), Vector3f(z2, y1), Vector3f(x1, y1, z1), Vector3f(z1, y1), Vector3f(x1, y2, z1), Vector3f(z1, y2), Vector3f(x1, y2, z2), Vector3f(z2, y2), Vector3f(x2, y1, z2), Vector3f(z2, y1), Vector3f(x2, y1, z1), Vector3f(z1, y1), Vector3f(x2, y2, z1), Vector3f(z1, y2), Vector3f(x2, y2, z2), Vector3f(z2, y2), Vector3f(x1, y1, z1), Vector3f(x1, y1), Vector3f(x2, y1, z1), Vector3f(x2, y1), Vector3f(x2, y2, z1), Vector3f(x2, y2), Vector3f(x1, y2, z1), Vector3f(x1, y2), Vector3f(x1, y1, z2), Vector3f(x1, y1), Vector3f(x2, y1, z2), Vector3f(x2, y1), Vector3f(x2, y2, z2), Vector3f(x2, y2), Vector3f(x1, y2, z2), Vector3f(x1, y2) }; GLushort CubeIndices[] = { 0, 1, 3, 3, 1, 2, 5, 4, 6, 6, 4, 7, 8, 9, 11, 11, 9, 10, 13, 12, 14, 14, 12, 15, 16, 17, 19, 19, 17, 18, 21, 20, 22, 22, 20, 23 }; for (int i = 0; i < sizeof(CubeIndices) / sizeof(CubeIndices[0]); ++i) AddIndex(CubeIndices[i] + GLushort(numVertices)); // Generate a quad for each box face for (int v = 0; v < 6 * 4; v++) { // Make vertices, with some token lighting Vertex vvv; vvv.Pos = Vert[v][0]; vvv.U = Vert[v][1].x; vvv.V = Vert[v][1].y; float dist1 = (vvv.Pos - Vector3f(-2, 4, -2)).Length(); float dist2 = (vvv.Pos - Vector3f(3, 4, -3)).Length(); float dist3 = (vvv.Pos - Vector3f(-4, 3, 25)).Length(); int bri = rand() % 160; float B = ((c >> 16) & 0xff) * (bri + 192.0f * (0.65f + 8 / dist1 + 1 / dist2 + 4 / dist3)) / 255.0f; float G = ((c >> 8) & 0xff) * (bri + 192.0f * (0.65f + 8 / dist1 + 1 / dist2 + 4 / dist3)) / 255.0f; float R = ((c >> 0) & 0xff) * (bri + 192.0f * (0.65f + 8 / dist1 + 1 / dist2 + 4 / dist3)) / 255.0f; vvv.C = (c & 0xff000000) + ((R > 255 ? 255 : DWORD(R)) << 16) + ((G > 255 ? 255 : DWORD(G)) << 8) + (B > 255 ? 255 : DWORD(B)); AddVertex(vvv); } } void Render(Matrix4f view, Matrix4f proj) { Matrix4f combined = proj * view * GetMatrix(); glUseProgram(Fill->program); glUniform1i(glGetUniformLocation(Fill->program, "Texture0"), 0); glUniformMatrix4fv(glGetUniformLocation(Fill->program, "matWVP"), 1, GL_TRUE, (FLOAT*)&combined); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, Fill->texture->texId); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer->buffer); GLuint posLoc = glGetAttribLocation(Fill->program, "Position"); GLuint colorLoc = glGetAttribLocation(Fill->program, "Color"); GLuint uvLoc = glGetAttribLocation(Fill->program, "TexCoord"); glEnableVertexAttribArray(posLoc); glEnableVertexAttribArray(colorLoc); glEnableVertexAttribArray(uvLoc); glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)OVR_OFFSETOF(Vertex, Pos)); glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)OVR_OFFSETOF(Vertex, C)); glVertexAttribPointer(uvLoc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)OVR_OFFSETOF(Vertex, U)); glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, NULL); glDisableVertexAttribArray(posLoc); glDisableVertexAttribArray(colorLoc); glDisableVertexAttribArray(uvLoc); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glUseProgram(0); } }; //------------------------------------------------------------------------- struct Scene { int numModels; Model * Models[100]; // 最大モデル数は100個(必要があれば増やす) void Add(Model * n) { Models[numModels++] = n; } void Render(Matrix4f view, Matrix4f proj) { // ブレンドを有効にする glEnable(GL_CULL_FACE); glFrontFace(GL_CW); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); for (int i = 0; i < numModels; ++i) { Models[i]->Render(view, proj); } glDisable(GL_BLEND); } GLuint CreateShader(GLenum type, const GLchar* src) { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &src, NULL); glCompileShader(shader); GLint r; glGetShaderiv(shader, GL_COMPILE_STATUS, &r); if (!r) { GLchar msg[1024]; glGetShaderInfoLog(shader, sizeof(msg), 0, msg); if (msg[0]) { OVR_DEBUG_LOG(("Compiling shader failed: %s\n", msg)); } return 0; } return shader; } GLchar* loadShaderFile(const char *filename) { GLchar* shaderSrc = NULL; FILE *fp = NULL; GLsizei length; int ret; fopen_s(&fp, filename, "rb"); if (fp != NULL) { fseek(fp, 0L, SEEK_END); length = ftell(fp); shaderSrc = (GLchar *)malloc(length + 1); if (shaderSrc != NULL) { fseek(fp, 0L, SEEK_SET); ret = fread((void *)shaderSrc, 1, length, fp) != (size_t)length; fclose(fp); } shaderSrc[length] = '\0'; } else { printf("Can't open the file: %s\n", filename); exit(1); } return shaderSrc; } void Init(int includeIntensiveGPUobject, const char* vsFileName, const char* fsFileName) { // Vertex Shader GLchar* VertexShaderSrc = loadShaderFile(vsFileName); // Fragment Shader GLchar* FragmentShaderSrc = loadShaderFile(fsFileName); GLuint vshader = CreateShader(GL_VERTEX_SHADER, VertexShaderSrc); GLuint fshader = CreateShader(GL_FRAGMENT_SHADER, FragmentShaderSrc); // Make textures ShaderFill * grid_material[4]; for (int k = 0; k < 4; ++k) { static DWORD tex_pixels[256 * 256]; for (int j = 0; j < 256; ++j) { for (int i = 0; i < 256; ++i) { if (k == 0) tex_pixels[j * 256 + i] = (((i >> 7) ^ (j >> 7)) & 1) ? 0xffb4b4b4 : 0xff505050;// floor if (k == 1) tex_pixels[j * 256 + i] = (((j / 4 & 15) == 0) || (((i / 4 & 15) == 0) && ((((i / 4 & 31) == 0) ^ ((j / 4 >> 4) & 1)) == 0))) ? 0xff3c3c3c : 0xffb4b4b4;// wall if (k == 2) tex_pixels[j * 256 + i] = (i / 4 == 0 || j / 4 == 0) ? 0xff505050 : 0xffb4b4b4;// ceiling if (k == 3) tex_pixels[j * 256 + i] = 0xffffffff;// blank } } TextureBuffer * generated_texture = new TextureBuffer(nullptr, false, false, Sizei(256, 256), 4, (unsigned char *)tex_pixels, 1); grid_material[k] = new ShaderFill(vshader, fshader, generated_texture); } // Construct geometry Model *m = nullptr; m = new Model(Vector3f(0, 0, 0), grid_material[0]); // Moving box m->AddSolidColorBox(-0.5f, 0.0f, -0.5f, +0.5f, 1.0f, 0.5f, 0xff404040); m->AllocateBuffers(); Add(m); glDeleteShader(vshader); glDeleteShader(fshader); free((void *)VertexShaderSrc); free((void *)FragmentShaderSrc); } Scene() : numModels(0) {} Scene(bool includeIntensiveGPUobject, const char *vsFileName, const char *fsFileName) : numModels(0) { Init(includeIntensiveGPUobject, vsFileName, fsFileName); } void Release() { while (numModels-- > 0) delete Models[numModels]; } ~Scene() { Release(); } };