2016-11-19 09:28:01 +00:00
|
|
|
#include "graphics/graphics.h"
|
2016-11-27 10:06:47 +00:00
|
|
|
#include "loaders/texture.h"
|
2017-02-07 09:13:39 +00:00
|
|
|
#include "loaders/font.h"
|
2017-04-13 02:48:17 +00:00
|
|
|
#include "event/event.h"
|
2017-06-10 22:34:35 +00:00
|
|
|
#include "filesystem/filesystem.h"
|
2017-01-21 03:55:54 +00:00
|
|
|
#include "math/mat4.h"
|
|
|
|
#include "math/vec3.h"
|
2016-11-19 09:28:01 +00:00
|
|
|
#include "util.h"
|
2017-08-10 03:02:02 +00:00
|
|
|
#include "lib/stb/stb_image.h"
|
2016-09-27 07:24:28 +00:00
|
|
|
#define _USE_MATH_DEFINES
|
2016-07-16 05:39:17 +00:00
|
|
|
#include <stdlib.h>
|
2017-04-16 23:56:49 +00:00
|
|
|
#include <stdio.h>
|
2016-09-27 07:24:28 +00:00
|
|
|
#include <math.h>
|
2016-09-14 00:02:23 +00:00
|
|
|
|
2016-09-27 06:48:09 +00:00
|
|
|
static GraphicsState state;
|
2016-07-07 07:04:24 +00:00
|
|
|
|
2017-04-13 02:48:17 +00:00
|
|
|
static void onCloseWindow(GLFWwindow* window) {
|
|
|
|
if (window == state.window) {
|
|
|
|
EventType type = EVENT_QUIT;
|
|
|
|
EventData data = { .quit = { 0 } };
|
|
|
|
Event event = { .type = type, .data = data };
|
|
|
|
lovrEventPush(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
// Base
|
|
|
|
|
2016-08-10 06:28:17 +00:00
|
|
|
void lovrGraphicsInit() {
|
2017-08-10 03:02:02 +00:00
|
|
|
//
|
2016-09-28 03:20:08 +00:00
|
|
|
}
|
|
|
|
|
2016-10-04 22:13:57 +00:00
|
|
|
void lovrGraphicsDestroy() {
|
2016-11-19 22:06:41 +00:00
|
|
|
lovrGraphicsSetShader(NULL);
|
2017-08-09 00:53:03 +00:00
|
|
|
lovrGraphicsSetFont(NULL);
|
2017-08-09 04:02:28 +00:00
|
|
|
for (int i = 0; i < DEFAULT_SHADER_COUNT; i++) {
|
|
|
|
if (state.defaultShaders[i]) lovrRelease(&state.defaultShaders[i]->ref);
|
|
|
|
}
|
|
|
|
if (state.defaultFont) lovrRelease(&state.defaultFont->ref);
|
|
|
|
if (state.defaultTexture) lovrRelease(&state.defaultTexture->ref);
|
2017-08-10 03:02:02 +00:00
|
|
|
glDeleteVertexArrays(1, &state.streamVAO);
|
2017-08-09 01:57:41 +00:00
|
|
|
glDeleteBuffers(1, &state.streamVBO);
|
|
|
|
glDeleteBuffers(1, &state.streamIBO);
|
|
|
|
vec_deinit(&state.streamData);
|
|
|
|
vec_deinit(&state.streamIndices);
|
2016-10-04 22:13:57 +00:00
|
|
|
}
|
|
|
|
|
2016-09-28 03:20:08 +00:00
|
|
|
void lovrGraphicsReset() {
|
2017-08-02 06:52:03 +00:00
|
|
|
int w = lovrGraphicsGetWidth();
|
|
|
|
int h = lovrGraphicsGetHeight();
|
|
|
|
float projection[16];
|
2016-11-27 18:57:36 +00:00
|
|
|
state.transform = 0;
|
2017-01-11 17:22:18 +00:00
|
|
|
state.canvas = 0;
|
2017-08-09 04:02:28 +00:00
|
|
|
state.defaultShader = -1;
|
2017-08-02 08:25:56 +00:00
|
|
|
lovrGraphicsSetBackgroundColor((Color) { 0, 0, 0, 0 });
|
2017-04-01 22:33:32 +00:00
|
|
|
lovrGraphicsSetBlendMode(BLEND_ALPHA, BLEND_ALPHA_MULTIPLY);
|
2017-08-02 08:25:56 +00:00
|
|
|
lovrGraphicsSetColor((Color) { 255, 255, 255, 255 });
|
2017-08-09 05:39:00 +00:00
|
|
|
lovrGraphicsSetCullingEnabled(0);
|
|
|
|
lovrGraphicsSetDefaultFilter((TextureFilter) { .mode = FILTER_TRILINEAR });
|
|
|
|
lovrGraphicsSetDepthTest(COMPARE_LEQUAL);
|
|
|
|
lovrGraphicsSetFont(NULL);
|
2016-10-01 20:48:31 +00:00
|
|
|
lovrGraphicsSetLineWidth(1);
|
2016-11-13 01:38:49 +00:00
|
|
|
lovrGraphicsSetPointSize(1);
|
2017-08-09 05:39:00 +00:00
|
|
|
lovrGraphicsSetShader(NULL);
|
2017-08-02 07:54:33 +00:00
|
|
|
lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE);
|
2016-11-23 05:07:33 +00:00
|
|
|
lovrGraphicsSetWireframe(0);
|
2017-08-09 05:39:00 +00:00
|
|
|
lovrGraphicsSetViewport(0, 0, w, h);
|
|
|
|
lovrGraphicsSetProjection(mat4_perspective(projection, .01f, 100.f, 67 * M_PI / 180., (float) w / h));
|
2017-02-18 23:29:32 +00:00
|
|
|
lovrGraphicsOrigin();
|
2016-08-10 06:28:17 +00:00
|
|
|
}
|
2016-07-07 07:04:24 +00:00
|
|
|
|
2016-09-17 03:11:11 +00:00
|
|
|
void lovrGraphicsClear(int color, int depth) {
|
2017-08-01 20:11:32 +00:00
|
|
|
if (!color && !depth) return;
|
|
|
|
glClear((color ? GL_COLOR_BUFFER_BIT : 0) | (depth ? GL_DEPTH_BUFFER_BIT : 0));
|
2016-07-07 07:04:24 +00:00
|
|
|
}
|
|
|
|
|
2016-08-10 06:28:17 +00:00
|
|
|
void lovrGraphicsPresent() {
|
2017-04-13 02:48:17 +00:00
|
|
|
glfwSwapBuffers(state.window);
|
2016-07-07 07:04:24 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 03:58:56 +00:00
|
|
|
void lovrGraphicsPrepare() {
|
2017-08-09 07:56:13 +00:00
|
|
|
Shader* shader = lovrGraphicsGetActiveShader();
|
|
|
|
|
|
|
|
if (!shader) {
|
|
|
|
shader = state.defaultShaders[state.defaultShader] = lovrShaderCreateDefault(state.defaultShader);
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:22:18 +00:00
|
|
|
mat4 transform = state.transforms[state.transform];
|
2017-08-02 06:59:53 +00:00
|
|
|
mat4 projection = state.canvases[state.canvas].projection;
|
2017-08-09 07:56:13 +00:00
|
|
|
lovrGraphicsBindProgram(shader->id);
|
|
|
|
lovrShaderBind(shader, transform, projection, state.color, 0);
|
2016-09-24 03:58:56 +00:00
|
|
|
}
|
|
|
|
|
2017-08-10 03:02:02 +00:00
|
|
|
void lovrGraphicsCreateWindow(int w, int h, int fullscreen, int msaa, const char* title, const char* icon) {
|
|
|
|
if (state.window) {
|
|
|
|
error("Window is already created");
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef EMSCRIPTEN
|
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
|
|
|
#else
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
|
|
glfwWindowHint(GLFW_SAMPLES, msaa);
|
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
|
|
|
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
|
|
|
if (fullscreen) {
|
|
|
|
glfwWindowHint(GLFW_RED_BITS, mode->redBits);
|
|
|
|
glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
|
|
|
|
glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
|
|
|
|
glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
|
|
|
|
}
|
|
|
|
|
|
|
|
state.window = glfwCreateWindow(w ? w : mode->width, h ? h : mode->height, title, fullscreen ? monitor : NULL, NULL);
|
|
|
|
if (!state.window) {
|
|
|
|
glfwTerminate();
|
|
|
|
error("Could not create window");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (icon) {
|
|
|
|
GLFWimage image;
|
|
|
|
image.pixels = stbi_load(icon, &image.width, &image.height, NULL, 3);
|
|
|
|
glfwSetWindowIcon(state.window, 1, &image);
|
|
|
|
free(image.pixels);
|
|
|
|
}
|
|
|
|
|
|
|
|
glfwMakeContextCurrent(state.window);
|
|
|
|
glfwSetWindowCloseCallback(state.window, onCloseWindow);
|
|
|
|
|
|
|
|
#ifndef EMSCRIPTEN
|
|
|
|
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
|
|
|
|
glfwSwapInterval(0);
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
|
|
|
#endif
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
glGenVertexArrays(1, &state.streamVAO);
|
|
|
|
glGenBuffers(1, &state.streamVBO);
|
|
|
|
glGenBuffers(1, &state.streamIBO);
|
|
|
|
vec_init(&state.streamData);
|
|
|
|
vec_init(&state.streamIndices);
|
|
|
|
lovrGraphicsReset();
|
|
|
|
atexit(lovrGraphicsDestroy);
|
|
|
|
}
|
|
|
|
|
|
|
|
int lovrGraphicsGetWidth() {
|
|
|
|
int width, height;
|
|
|
|
glfwGetFramebufferSize(state.window, &width, &height);
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lovrGraphicsGetHeight() {
|
|
|
|
int width, height;
|
|
|
|
glfwGetFramebufferSize(state.window, &width, &height);
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
// State
|
|
|
|
|
2017-08-02 08:25:56 +00:00
|
|
|
Color lovrGraphicsGetBackgroundColor() {
|
|
|
|
return state.backgroundColor;
|
2016-07-28 02:48:59 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 08:25:56 +00:00
|
|
|
void lovrGraphicsSetBackgroundColor(Color color) {
|
|
|
|
state.backgroundColor = color;
|
|
|
|
glClearColor(color.r / 255., color.g / 255., color.b / 255., color.a / 255.);
|
2016-07-28 02:48:59 +00:00
|
|
|
}
|
|
|
|
|
2017-03-12 11:03:36 +00:00
|
|
|
void lovrGraphicsGetBlendMode(BlendMode* mode, BlendAlphaMode* alphaMode) {
|
|
|
|
*mode = state.blendMode;
|
|
|
|
*alphaMode = state.blendAlphaMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetBlendMode(BlendMode mode, BlendAlphaMode alphaMode) {
|
|
|
|
GLenum srcRGB = mode == BLEND_MULTIPLY ? GL_DST_COLOR : GL_ONE;
|
|
|
|
|
|
|
|
if (srcRGB == GL_ONE && alphaMode == BLEND_ALPHA_MULTIPLY) {
|
|
|
|
srcRGB = GL_SRC_ALPHA;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case BLEND_ALPHA:
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
|
|
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BLEND_ADD:
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
|
|
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BLEND_SUBTRACT:
|
|
|
|
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
|
|
|
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BLEND_MULTIPLY:
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
|
|
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_DST_COLOR, GL_ZERO);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BLEND_LIGHTEN:
|
2017-06-18 04:09:03 +00:00
|
|
|
glBlendEquation(GL_MAX);
|
|
|
|
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
2017-03-12 11:03:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case BLEND_DARKEN:
|
2017-06-18 04:09:03 +00:00
|
|
|
glBlendEquation(GL_MIN);
|
|
|
|
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
2017-03-12 11:03:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case BLEND_SCREEN:
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
|
|
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BLEND_REPLACE:
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
|
|
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 08:25:56 +00:00
|
|
|
Color lovrGraphicsGetColor() {
|
|
|
|
return state.color;
|
2016-09-29 03:11:58 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 08:25:56 +00:00
|
|
|
void lovrGraphicsSetColor(Color color) {
|
|
|
|
state.color = color;
|
2016-09-29 03:11:58 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
int lovrGraphicsIsCullingEnabled() {
|
|
|
|
return state.culling;
|
2016-09-14 00:02:23 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
void lovrGraphicsSetCullingEnabled(int culling) {
|
|
|
|
if (culling != state.culling) {
|
|
|
|
state.culling = culling;
|
|
|
|
if (culling) {
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_CULL_FACE);
|
2016-11-19 22:06:41 +00:00
|
|
|
}
|
|
|
|
}
|
2016-07-16 02:17:27 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
TextureFilter lovrGraphicsGetDefaultFilter() {
|
|
|
|
return state.defaultFilter;
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
void lovrGraphicsSetDefaultFilter(TextureFilter filter) {
|
|
|
|
state.defaultFilter = filter;
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
CompareMode lovrGraphicsGetDepthTest() {
|
|
|
|
return state.depthTest;
|
2017-02-17 08:48:43 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
void lovrGraphicsSetDepthTest(CompareMode depthTest) {
|
|
|
|
if (state.depthTest != depthTest) {
|
|
|
|
state.depthTest = depthTest;
|
|
|
|
glDepthFunc(depthTest);
|
|
|
|
if (depthTest) {
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
}
|
2017-02-06 04:30:17 +00:00
|
|
|
}
|
2016-11-27 02:58:58 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 08:36:29 +00:00
|
|
|
Font* lovrGraphicsGetFont() {
|
2017-08-09 06:49:17 +00:00
|
|
|
if (!state.font) {
|
|
|
|
if (!state.defaultFont) {
|
|
|
|
FontData* fontData = lovrFontDataCreate(NULL, 32);
|
|
|
|
state.defaultFont = lovrFontCreate(fontData);
|
|
|
|
}
|
|
|
|
|
2017-08-08 08:36:29 +00:00
|
|
|
lovrGraphicsSetFont(state.defaultFont);
|
|
|
|
}
|
|
|
|
|
|
|
|
return state.font;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetFont(Font* font) {
|
|
|
|
if (state.font) {
|
|
|
|
lovrRelease(&state.font->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
state.font = font;
|
|
|
|
|
|
|
|
if (font) {
|
|
|
|
lovrRetain(&state.font->ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
GraphicsLimits lovrGraphicsGetLimits() {
|
|
|
|
if (!state.limits.initialized) {
|
|
|
|
glGetFloatv(GL_POINT_SIZE_RANGE, state.limits.pointSizes);
|
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.limits.textureSize);
|
|
|
|
glGetIntegerv(GL_MAX_SAMPLES, &state.limits.textureMSAA);
|
|
|
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &state.limits.textureAnisotropy);
|
|
|
|
state.limits.initialized = 1;
|
|
|
|
}
|
2017-01-12 09:26:44 +00:00
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
return state.limits;
|
2017-03-12 05:19:26 +00:00
|
|
|
}
|
|
|
|
|
2016-10-01 20:48:31 +00:00
|
|
|
float lovrGraphicsGetLineWidth() {
|
|
|
|
return state.lineWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetLineWidth(float width) {
|
|
|
|
state.lineWidth = width;
|
|
|
|
glLineWidth(width);
|
|
|
|
}
|
|
|
|
|
2016-11-13 01:38:49 +00:00
|
|
|
float lovrGraphicsGetPointSize() {
|
|
|
|
return state.pointSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetPointSize(float size) {
|
2017-08-01 19:16:09 +00:00
|
|
|
#ifndef EMSCRIPTEN
|
2017-06-18 04:09:03 +00:00
|
|
|
state.pointSize = size;
|
|
|
|
glPointSize(size);
|
|
|
|
#endif
|
2016-11-13 01:38:49 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 08:32:15 +00:00
|
|
|
Shader* lovrGraphicsGetShader() {
|
|
|
|
return state.shader;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetShader(Shader* shader) {
|
|
|
|
if (shader != state.shader) {
|
|
|
|
if (state.shader) {
|
|
|
|
lovrRelease(&state.shader->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
state.shader = shader;
|
2017-08-09 04:02:28 +00:00
|
|
|
|
|
|
|
if (shader) {
|
|
|
|
lovrRetain(&state.shader->ref);
|
|
|
|
}
|
2017-08-08 08:32:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
Winding lovrGraphicsGetWinding() {
|
|
|
|
return state.winding;
|
2016-10-03 19:02:49 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
void lovrGraphicsSetWinding(Winding winding) {
|
|
|
|
state.winding = winding;
|
|
|
|
glFrontFace(winding);
|
2016-10-03 19:02:49 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
int lovrGraphicsIsWireframe() {
|
|
|
|
return state.wireframe;
|
2016-10-03 19:02:49 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
void lovrGraphicsSetWireframe(int wireframe) {
|
|
|
|
#ifndef EMSCRIPTEN
|
|
|
|
if (state.wireframe != wireframe) {
|
|
|
|
state.wireframe = wireframe;
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL);
|
|
|
|
}
|
|
|
|
#endif
|
2016-10-03 19:02:49 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
// Transforms
|
|
|
|
|
2016-09-21 07:55:53 +00:00
|
|
|
int lovrGraphicsPush() {
|
2016-11-27 18:57:36 +00:00
|
|
|
if (++state.transform >= MAX_TRANSFORMS) { return 1; }
|
|
|
|
memcpy(state.transforms[state.transform], state.transforms[state.transform - 1], 16 * sizeof(float));
|
2016-09-21 07:55:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lovrGraphicsPop() {
|
2016-11-27 18:57:36 +00:00
|
|
|
return --state.transform < 0;
|
2016-09-21 07:55:53 +00:00
|
|
|
}
|
|
|
|
|
2016-09-21 22:26:05 +00:00
|
|
|
void lovrGraphicsOrigin() {
|
2017-01-18 08:51:09 +00:00
|
|
|
mat4_identity(state.transforms[state.transform]);
|
2016-09-21 22:26:05 +00:00
|
|
|
}
|
|
|
|
|
2016-09-23 04:53:17 +00:00
|
|
|
void lovrGraphicsTranslate(float x, float y, float z) {
|
2016-11-27 18:57:36 +00:00
|
|
|
mat4_translate(state.transforms[state.transform], x, y, z);
|
2016-09-23 04:53:17 +00:00
|
|
|
}
|
|
|
|
|
2016-12-02 01:32:39 +00:00
|
|
|
void lovrGraphicsRotate(float angle, float ax, float ay, float az) {
|
2017-01-20 02:04:45 +00:00
|
|
|
mat4_rotate(state.transforms[state.transform], angle, ax, ay, az);
|
2016-09-23 04:53:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsScale(float x, float y, float z) {
|
2016-11-27 18:57:36 +00:00
|
|
|
mat4_scale(state.transforms[state.transform], x, y, z);
|
2016-09-23 04:53:17 +00:00
|
|
|
}
|
|
|
|
|
2016-11-02 03:48:04 +00:00
|
|
|
void lovrGraphicsMatrixTransform(mat4 transform) {
|
2016-11-27 18:57:36 +00:00
|
|
|
mat4_multiply(state.transforms[state.transform], transform);
|
2016-09-29 07:21:38 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
// Primitives
|
2016-09-29 05:10:03 +00:00
|
|
|
|
2017-08-02 03:00:50 +00:00
|
|
|
static void lovrGraphicsSetShapeData(float* data, int length) {
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_clear(&state.streamData);
|
|
|
|
vec_pusharr(&state.streamData, data, length);
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 03:00:50 +00:00
|
|
|
static void lovrGraphicsSetIndexData(unsigned int* data, int length) {
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_clear(&state.streamIndices);
|
|
|
|
vec_pusharr(&state.streamIndices, data, length);
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 03:00:50 +00:00
|
|
|
static void lovrGraphicsDrawPrimitive(GLenum mode, int hasNormals, int hasTexCoords, int useIndices) {
|
2017-01-13 09:59:00 +00:00
|
|
|
int stride = 3 + (hasNormals ? 3 : 0) + (hasTexCoords ? 2 : 0);
|
|
|
|
int strideBytes = stride * sizeof(float);
|
2017-08-09 01:57:41 +00:00
|
|
|
float* data = state.streamData.data;
|
|
|
|
unsigned int* indices = state.streamIndices.data;
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
lovrGraphicsPrepare();
|
2017-08-09 01:57:41 +00:00
|
|
|
lovrGraphicsBindVertexArray(state.streamVAO);
|
|
|
|
lovrGraphicsBindVertexBuffer(state.streamVBO);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, state.streamData.length * sizeof(float), data, GL_STREAM_DRAW);
|
2017-01-13 09:59:00 +00:00
|
|
|
glEnableVertexAttribArray(LOVR_SHADER_POSITION);
|
|
|
|
glVertexAttribPointer(LOVR_SHADER_POSITION, 3, GL_FLOAT, GL_FALSE, strideBytes, (void*) 0);
|
2016-09-30 06:18:51 +00:00
|
|
|
|
2017-01-13 09:59:00 +00:00
|
|
|
if (hasNormals) {
|
|
|
|
glEnableVertexAttribArray(LOVR_SHADER_NORMAL);
|
|
|
|
glVertexAttribPointer(LOVR_SHADER_NORMAL, 3, GL_FLOAT, GL_FALSE, strideBytes, (void*) (3 * sizeof(float)));
|
2016-10-07 06:34:35 +00:00
|
|
|
} else {
|
2017-01-13 09:59:00 +00:00
|
|
|
glDisableVertexAttribArray(LOVR_SHADER_NORMAL);
|
2016-09-30 06:18:51 +00:00
|
|
|
}
|
2016-09-29 07:00:02 +00:00
|
|
|
|
2017-01-13 09:59:00 +00:00
|
|
|
if (hasTexCoords) {
|
|
|
|
void* offset = (void*) ((hasNormals ? 6 : 3) * sizeof(float));
|
|
|
|
glEnableVertexAttribArray(LOVR_SHADER_TEX_COORD);
|
|
|
|
glVertexAttribPointer(LOVR_SHADER_TEX_COORD, 2, GL_FLOAT, GL_FALSE, strideBytes, offset);
|
|
|
|
} else {
|
|
|
|
glDisableVertexAttribArray(LOVR_SHADER_TEX_COORD);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (useIndices) {
|
2017-08-09 01:57:41 +00:00
|
|
|
lovrGraphicsBindIndexBuffer(state.streamIBO);
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, state.streamIndices.length * sizeof(unsigned int), indices, GL_STREAM_DRAW);
|
|
|
|
glDrawElements(mode, state.streamIndices.length, GL_UNSIGNED_INT, NULL);
|
2017-01-13 09:59:00 +00:00
|
|
|
} else {
|
2017-08-09 01:57:41 +00:00
|
|
|
glDrawArrays(mode, 0, state.streamData.length / stride);
|
2017-01-13 09:59:00 +00:00
|
|
|
}
|
2016-09-30 02:39:25 +00:00
|
|
|
}
|
|
|
|
|
2016-11-08 07:16:33 +00:00
|
|
|
void lovrGraphicsPoints(float* points, int count) {
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsBindTexture(NULL);
|
2017-08-09 04:02:28 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(points, count);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_POINTS, 0, 0, 0);
|
2016-11-08 07:16:33 +00:00
|
|
|
}
|
|
|
|
|
2016-09-30 02:39:25 +00:00
|
|
|
void lovrGraphicsLine(float* points, int count) {
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsBindTexture(NULL);
|
2017-08-09 04:02:28 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(points, count);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_LINE_STRIP, 0, 0, 0);
|
2016-09-29 07:00:02 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 04:43:22 +00:00
|
|
|
void lovrGraphicsTriangle(DrawMode mode, float* points) {
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsBindTexture(NULL);
|
2017-08-09 04:02:28 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2017-03-12 23:57:27 +00:00
|
|
|
|
2016-11-23 04:43:22 +00:00
|
|
|
if (mode == DRAW_MODE_LINE) {
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(points, 9);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, 0, 0, 0);
|
2016-11-23 04:43:22 +00:00
|
|
|
} else {
|
2017-01-20 02:50:51 +00:00
|
|
|
float normal[3];
|
|
|
|
vec3_cross(vec3_init(normal, &points[0]), &points[3]);
|
2016-11-23 04:43:22 +00:00
|
|
|
|
|
|
|
float data[18] = {
|
2017-01-20 02:50:51 +00:00
|
|
|
points[0], points[1], points[2], normal[0], normal[1], normal[2],
|
|
|
|
points[3], points[4], points[5], normal[0], normal[1], normal[2],
|
|
|
|
points[6], points[7], points[8], normal[0], normal[1], normal[2]
|
2016-11-23 04:43:22 +00:00
|
|
|
};
|
|
|
|
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(data, 18);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 1, 0, 0);
|
2016-11-23 04:43:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-18 20:07:18 +00:00
|
|
|
void lovrGraphicsPlane(DrawMode mode, Texture* texture, mat4 transform) {
|
2016-10-04 03:56:45 +00:00
|
|
|
lovrGraphicsPush();
|
2017-01-21 04:43:00 +00:00
|
|
|
lovrGraphicsMatrixTransform(transform);
|
2016-10-04 03:56:45 +00:00
|
|
|
|
|
|
|
if (mode == DRAW_MODE_LINE) {
|
2016-10-07 06:34:35 +00:00
|
|
|
float points[] = {
|
|
|
|
-.5, .5, 0,
|
|
|
|
.5, .5, 0,
|
|
|
|
.5, -.5, 0,
|
|
|
|
-.5, -.5, 0
|
|
|
|
};
|
|
|
|
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsBindTexture(NULL);
|
2017-08-09 07:56:13 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(points, 12);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, 0, 0, 0);
|
2016-10-04 03:56:45 +00:00
|
|
|
} else if (mode == DRAW_MODE_FILL) {
|
2016-10-07 06:34:35 +00:00
|
|
|
float data[] = {
|
2017-01-13 09:59:00 +00:00
|
|
|
-.5, .5, 0, 0, 0, -1, 0, 0,
|
|
|
|
-.5, -.5, 0, 0, 0, -1, 0, 1,
|
|
|
|
.5, .5, 0, 0, 0, -1, 1, 0,
|
|
|
|
.5, -.5, 0, 0, 0, -1, 1, 1
|
2016-10-07 06:34:35 +00:00
|
|
|
};
|
|
|
|
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsBindTexture(texture);
|
2017-08-09 07:56:13 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(data, 32);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 1, 1, 0);
|
2016-10-04 03:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lovrGraphicsPop();
|
|
|
|
}
|
|
|
|
|
2017-01-13 09:59:00 +00:00
|
|
|
void lovrGraphicsPlaneFullscreen(Texture* texture) {
|
|
|
|
float data[] = {
|
2017-01-15 21:49:24 +00:00
|
|
|
-1, 1, 0, 0, 1,
|
|
|
|
-1, -1, 0, 0, 0,
|
|
|
|
1, 1, 0, 1, 1,
|
|
|
|
1, -1, 0, 1, 0
|
2017-01-13 09:59:00 +00:00
|
|
|
};
|
|
|
|
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsBindTexture(texture);
|
2017-08-09 04:02:28 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_FULLSCREEN);
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(data, 20);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 0, 1, 0);
|
2017-01-13 09:59:00 +00:00
|
|
|
}
|
|
|
|
|
2017-06-22 02:42:34 +00:00
|
|
|
void lovrGraphicsBox(DrawMode mode, Texture* texture, mat4 transform) {
|
2017-08-09 04:02:28 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2016-10-01 19:53:15 +00:00
|
|
|
lovrGraphicsPush();
|
2017-01-20 03:11:42 +00:00
|
|
|
lovrGraphicsMatrixTransform(transform);
|
2016-10-01 19:10:38 +00:00
|
|
|
|
2016-10-01 19:53:15 +00:00
|
|
|
if (mode == DRAW_MODE_LINE) {
|
2016-10-07 06:34:35 +00:00
|
|
|
float points[] = {
|
|
|
|
// Front
|
|
|
|
-.5, .5, -.5,
|
|
|
|
.5, .5, -.5,
|
|
|
|
.5, -.5, -.5,
|
|
|
|
-.5, -.5, -.5,
|
|
|
|
|
|
|
|
// Back
|
|
|
|
-.5, .5, .5,
|
|
|
|
.5, .5, .5,
|
|
|
|
.5, -.5, .5,
|
|
|
|
-.5, -.5, .5
|
|
|
|
};
|
|
|
|
|
2016-10-01 19:10:38 +00:00
|
|
|
unsigned int indices[] = {
|
2016-10-01 19:53:15 +00:00
|
|
|
0, 1, 1, 2, 2, 3, 3, 0, // Front
|
|
|
|
4, 5, 5, 6, 6, 7, 7, 4, // Back
|
2016-10-01 19:10:38 +00:00
|
|
|
0, 4, 1, 5, 2, 6, 3, 7 // Connections
|
|
|
|
};
|
|
|
|
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsBindTexture(NULL);
|
2017-08-09 07:56:13 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(points, 24);
|
|
|
|
lovrGraphicsSetIndexData(indices, 24);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_LINES, 0, 0, 1);
|
2016-10-01 19:10:38 +00:00
|
|
|
} else {
|
2016-10-07 06:34:35 +00:00
|
|
|
float data[] = {
|
|
|
|
// Front
|
2017-01-15 21:49:24 +00:00
|
|
|
-.5, -.5, -.5, 0, 0, -1, 0, 0,
|
|
|
|
.5, -.5, -.5, 0, 0, -1, 1, 0,
|
|
|
|
-.5, .5, -.5, 0, 0, -1, 0, 1,
|
|
|
|
.5, .5, -.5, 0, 0, -1, 1, 1,
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
// Right
|
2017-01-15 21:49:24 +00:00
|
|
|
.5, .5, -.5, 1, 0, 0, 0, 1,
|
|
|
|
.5, -.5, -.5, 1, 0, 0, 0, 0,
|
|
|
|
.5, .5, .5, 1, 0, 0, 1, 1,
|
|
|
|
.5, -.5, .5, 1, 0, 0, 1, 0,
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
// Back
|
2017-01-15 21:49:24 +00:00
|
|
|
.5, -.5, .5, 0, 0, 1, 0, 0,
|
|
|
|
-.5, -.5, .5, 0, 0, 1, 1, 0,
|
|
|
|
.5, .5, .5, 0, 0, 1, 0, 1,
|
|
|
|
-.5, .5, .5, 0, 0, 1, 1, 1,
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
// Left
|
2017-01-15 21:49:24 +00:00
|
|
|
-.5, .5, .5, -1, 0, 0, 0, 1,
|
|
|
|
-.5, -.5, .5, -1, 0, 0, 0, 0,
|
|
|
|
-.5, .5, -.5, -1, 0, 0, 1, 1,
|
|
|
|
-.5, -.5, -.5, -1, 0, 0, 1, 0,
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
// Bottom
|
2017-01-15 21:49:24 +00:00
|
|
|
-.5, -.5, -.5, 0, -1, 0, 0, 0,
|
|
|
|
-.5, -.5, .5, 0, -1, 0, 0, 1,
|
|
|
|
.5, -.5, -.5, 0, -1, 0, 1, 0,
|
|
|
|
.5, -.5, .5, 0, -1, 0, 1, 1,
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
// Adjust
|
2017-01-15 21:49:24 +00:00
|
|
|
.5, -.5, .5, 0, 1, 0, 0, 1,
|
|
|
|
-.5, .5, -.5, 0, 1, 0, 0, 1,
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
// Top
|
2017-01-15 21:49:24 +00:00
|
|
|
-.5, .5, -.5, 0, 1, 0, 0, 1,
|
|
|
|
.5, .5, -.5, 0, 1, 0, 1, 1,
|
|
|
|
-.5, .5, .5, 0, 1, 0, 0, 0,
|
|
|
|
.5, .5, .5, 0, 1, 0, 1, 0
|
2016-10-01 19:53:15 +00:00
|
|
|
};
|
|
|
|
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsBindTexture(texture);
|
2017-08-09 07:56:13 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2017-02-03 23:16:30 +00:00
|
|
|
lovrGraphicsSetShapeData(data, 208);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 1, 1, 0);
|
2016-10-01 19:10:38 +00:00
|
|
|
}
|
2016-10-01 19:53:15 +00:00
|
|
|
|
|
|
|
lovrGraphicsPop();
|
2016-09-30 06:18:51 +00:00
|
|
|
}
|
2016-10-24 22:02:23 +00:00
|
|
|
|
2017-06-21 03:54:22 +00:00
|
|
|
void lovrGraphicsCylinder(float x1, float y1, float z1, float x2, float y2, float z2, float r1, float r2, int capped, int segments) {
|
|
|
|
float axis[3] = { x1 - x2, y1 - y2, z1 - z2 };
|
|
|
|
float n[3] = { x1 - x2, y1 - y2, z1 - z2 };
|
|
|
|
float p[3];
|
|
|
|
float q[3];
|
|
|
|
|
|
|
|
int stride = 6;
|
|
|
|
int dataSize = stride * ((capped && r1) * (segments + 2) + (capped && r2) * (segments + 2) + 2 * (segments + 1));
|
|
|
|
int indexSize = 3 * segments * ((capped && r1) + (capped && r2) + 2);
|
|
|
|
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_clear(&state.streamData);
|
|
|
|
vec_reserve(&state.streamData, dataSize);
|
|
|
|
state.streamData.length = 0;
|
|
|
|
float* data = state.streamData.data;
|
2017-06-21 03:54:22 +00:00
|
|
|
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_clear(&state.streamIndices);
|
|
|
|
vec_reserve(&state.streamIndices, indexSize);
|
|
|
|
state.streamIndices.length = 0;
|
|
|
|
unsigned int* indices = state.streamIndices.data;
|
2017-06-21 03:54:22 +00:00
|
|
|
|
|
|
|
vec3_init(p, n);
|
|
|
|
|
|
|
|
if (n[0] == 0 && n[2] == 0) {
|
|
|
|
p[0] += 1;
|
|
|
|
} else {
|
|
|
|
p[1] += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vec3_init(q, p);
|
|
|
|
vec3_cross(q, n);
|
|
|
|
vec3_cross(n, q);
|
|
|
|
vec3_init(p, n);
|
|
|
|
vec3_normalize(p);
|
|
|
|
vec3_normalize(q);
|
|
|
|
vec3_normalize(axis);
|
|
|
|
|
|
|
|
#define PUSH_CYLINDER_VERTEX(x, y, z, nx, ny, nz) \
|
2017-08-09 01:57:41 +00:00
|
|
|
data[state.streamData.length++] = x; \
|
|
|
|
data[state.streamData.length++] = y; \
|
|
|
|
data[state.streamData.length++] = z; \
|
|
|
|
data[state.streamData.length++] = nx; \
|
|
|
|
data[state.streamData.length++] = ny; \
|
|
|
|
data[state.streamData.length++] = nz;
|
2017-06-21 03:54:22 +00:00
|
|
|
|
|
|
|
#define PUSH_CYLINDER_TRIANGLE(i1, i2, i3) \
|
2017-08-09 01:57:41 +00:00
|
|
|
indices[state.streamIndices.length++] = i1; \
|
|
|
|
indices[state.streamIndices.length++] = i2; \
|
|
|
|
indices[state.streamIndices.length++] = i3;
|
2017-06-21 03:54:22 +00:00
|
|
|
|
|
|
|
// Ring
|
2017-08-09 01:57:41 +00:00
|
|
|
int ringOffset = state.streamData.length / 6;
|
2017-06-21 03:54:22 +00:00
|
|
|
for (int i = 0; i <= segments; i++) {
|
|
|
|
float theta = i * (2 * M_PI) / segments;
|
|
|
|
|
|
|
|
n[0] = cos(theta) * p[0] + sin(theta) * q[0];
|
|
|
|
n[1] = cos(theta) * p[1] + sin(theta) * q[1];
|
|
|
|
n[2] = cos(theta) * p[2] + sin(theta) * q[2];
|
|
|
|
|
|
|
|
PUSH_CYLINDER_VERTEX(x1 + r1 * n[0], y1 + r1 * n[1], z1 + r1 * n[2], n[0], n[1], n[2]);
|
|
|
|
PUSH_CYLINDER_VERTEX(x2 + r2 * n[0], y2 + r2 * n[1], z2 + r2 * n[2], n[0], n[1], n[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Top
|
2017-08-09 01:57:41 +00:00
|
|
|
int topOffset = state.streamData.length / 6;
|
2017-06-21 03:54:22 +00:00
|
|
|
if (capped && r1 != 0) {
|
|
|
|
PUSH_CYLINDER_VERTEX(x1, y1, z1, axis[0], axis[1], axis[2]);
|
|
|
|
|
|
|
|
for (int i = 0; i <= segments; i++) {
|
|
|
|
int j = i * 2 * stride;
|
|
|
|
PUSH_CYLINDER_VERTEX(data[j + 0], data[j + 1], data[j + 2], axis[0], axis[1], axis[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bottom
|
2017-08-09 01:57:41 +00:00
|
|
|
int bottomOffset = state.streamData.length / 6;
|
2017-06-21 03:54:22 +00:00
|
|
|
if (capped && r2 != 0) {
|
|
|
|
PUSH_CYLINDER_VERTEX(x2, y2, z2, -axis[0], -axis[1], -axis[2]);
|
|
|
|
|
|
|
|
for (int i = 0; i <= segments; i++) {
|
|
|
|
int j = i * 2 * stride + stride;
|
|
|
|
PUSH_CYLINDER_VERTEX(data[j + 0], data[j + 1], data[j + 2], -axis[0], -axis[1], -axis[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Indices
|
|
|
|
for (int i = 0; i < segments; i++) {
|
|
|
|
int j = ringOffset + 2 * i;
|
|
|
|
PUSH_CYLINDER_TRIANGLE(j, j + 1, j + 2);
|
|
|
|
PUSH_CYLINDER_TRIANGLE(j + 1, j + 3, j + 2);
|
|
|
|
|
|
|
|
if (capped && r1 != 0) {
|
|
|
|
PUSH_CYLINDER_TRIANGLE(topOffset, topOffset + i + 1, topOffset + i + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (capped && r2 != 0) {
|
|
|
|
PUSH_CYLINDER_TRIANGLE(bottomOffset, bottomOffset + i + 1, bottomOffset + i + 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-22 06:10:45 +00:00
|
|
|
lovrGraphicsBindTexture(NULL);
|
2017-08-09 07:56:13 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
2017-06-21 03:54:22 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 1, 0, 1);
|
|
|
|
#undef PUSH_CYLINDER_VERTEX
|
|
|
|
#undef PUSH_CYLINDER_TRIANGLE
|
|
|
|
}
|
|
|
|
|
2017-08-09 01:51:52 +00:00
|
|
|
void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox* skybox) {
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_clear(&state.streamData);
|
|
|
|
vec_clear(&state.streamIndices);
|
2017-06-22 06:10:45 +00:00
|
|
|
|
|
|
|
for (int i = 0; i <= segments; i++) {
|
|
|
|
float v = i / (float) segments;
|
|
|
|
for (int j = 0; j <= segments; j++) {
|
|
|
|
float u = j / (float) segments;
|
|
|
|
|
|
|
|
float x = -cos(u * 2 * M_PI) * sin(v * M_PI);
|
|
|
|
float y = cos(v * M_PI);
|
|
|
|
float z = sin(u * 2 * M_PI) * sin(v * M_PI);
|
|
|
|
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_push(&state.streamData, x);
|
|
|
|
vec_push(&state.streamData, y);
|
|
|
|
vec_push(&state.streamData, z);
|
2017-06-22 06:10:45 +00:00
|
|
|
|
2017-08-09 01:51:52 +00:00
|
|
|
if (!skybox) {
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_push(&state.streamData, x);
|
|
|
|
vec_push(&state.streamData, y);
|
|
|
|
vec_push(&state.streamData, z);
|
2017-08-09 01:51:52 +00:00
|
|
|
}
|
2017-06-22 06:10:45 +00:00
|
|
|
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_push(&state.streamData, u);
|
|
|
|
vec_push(&state.streamData, v);
|
2017-06-22 06:10:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < segments; i++) {
|
|
|
|
unsigned int offset0 = i * (segments + 1);
|
|
|
|
unsigned int offset1 = (i + 1) * (segments + 1);
|
|
|
|
for (int j = 0; j < segments; j++) {
|
|
|
|
unsigned int index0 = offset0 + j;
|
|
|
|
unsigned int index1 = offset1 + j;
|
2017-08-09 01:57:41 +00:00
|
|
|
vec_push(&state.streamIndices, index0);
|
|
|
|
vec_push(&state.streamIndices, index1);
|
|
|
|
vec_push(&state.streamIndices, index0 + 1);
|
|
|
|
vec_push(&state.streamIndices, index1);
|
|
|
|
vec_push(&state.streamIndices, index1 + 1);
|
|
|
|
vec_push(&state.streamIndices, index0 + 1);
|
2017-06-22 06:10:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-09 07:56:13 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
|
|
|
|
2017-08-09 01:51:52 +00:00
|
|
|
if (skybox) {
|
|
|
|
Texture* oldTexture = lovrGraphicsGetTexture();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, skybox->texture);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 0, 1, 1);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, oldTexture->id);
|
|
|
|
} else {
|
|
|
|
lovrGraphicsBindTexture(texture);
|
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsMatrixTransform(transform);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 1, 1, 1);
|
|
|
|
lovrGraphicsPop();
|
|
|
|
}
|
2017-06-22 06:10:45 +00:00
|
|
|
}
|
|
|
|
|
2016-10-24 22:02:23 +00:00
|
|
|
void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az) {
|
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsOrigin();
|
2016-12-02 01:32:39 +00:00
|
|
|
lovrGraphicsRotate(angle, ax, ay, az);
|
2017-08-09 01:51:52 +00:00
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
int wasCulling = lovrGraphicsIsCullingEnabled();
|
|
|
|
lovrGraphicsSetCullingEnabled(0);
|
2016-10-24 22:02:23 +00:00
|
|
|
|
2017-03-12 23:45:24 +00:00
|
|
|
if (skybox->type == SKYBOX_CUBE) {
|
|
|
|
float cube[] = {
|
|
|
|
// Front
|
|
|
|
1.f, -1.f, -1.f,
|
|
|
|
1.f, 1.f, -1.f,
|
|
|
|
-1.f, -1.f, -1.f,
|
|
|
|
-1.f, 1.f, -1.f,
|
2016-10-24 22:02:23 +00:00
|
|
|
|
2017-03-12 23:45:24 +00:00
|
|
|
// Left
|
|
|
|
-1.f, 1.f, -1.f,
|
|
|
|
-1.f, 1.f, 1.f,
|
|
|
|
-1.f, -1.f, -1.f,
|
|
|
|
-1.f, -1.f, 1.f,
|
2017-01-29 07:19:28 +00:00
|
|
|
|
2017-03-12 23:45:24 +00:00
|
|
|
// Back
|
|
|
|
-1.f, -1.f, 1.f,
|
|
|
|
1.f, -1.f, 1.f,
|
|
|
|
-1.f, 1.f, 1.f,
|
|
|
|
1.f, 1.f, 1.f,
|
2016-10-24 22:02:23 +00:00
|
|
|
|
2017-03-12 23:45:24 +00:00
|
|
|
// Right
|
|
|
|
1.f, 1.f, 1.f,
|
|
|
|
1.f, -1.f, 1.f,
|
|
|
|
1.f, 1.f, -1.f,
|
|
|
|
1.f, -1.f, -1.f,
|
|
|
|
|
|
|
|
// Bottom
|
|
|
|
1.f, -1.f, -1.f,
|
|
|
|
1.f, -1.f, 1.f,
|
|
|
|
-1.f, -1.f, -1.f,
|
|
|
|
-1.f, -1.f, 1.f,
|
|
|
|
|
|
|
|
// Adjust
|
|
|
|
-1.f, -1.f, 1.f,
|
|
|
|
-1.f, 1.f, -1.f,
|
2016-10-24 22:02:23 +00:00
|
|
|
|
2017-03-12 23:45:24 +00:00
|
|
|
// Top
|
|
|
|
-1.f, 1.f, -1.f,
|
|
|
|
-1.f, 1.f, 1.f,
|
|
|
|
1.f, 1.f, -1.f,
|
|
|
|
1.f, 1.f, 1.f
|
|
|
|
};
|
|
|
|
|
2017-03-31 01:48:03 +00:00
|
|
|
lovrGraphicsSetShapeData(cube, 78);
|
2017-03-12 23:45:24 +00:00
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox->texture);
|
2017-08-09 04:02:28 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_SKYBOX);
|
2017-03-12 23:57:27 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 0, 0, 0);
|
2017-03-12 23:45:24 +00:00
|
|
|
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
} else if (skybox->type == SKYBOX_PANORAMA) {
|
2017-08-09 01:51:52 +00:00
|
|
|
lovrGraphicsSphere(NULL, NULL, 30, skybox);
|
2017-03-12 23:45:24 +00:00
|
|
|
}
|
2016-10-24 22:02:23 +00:00
|
|
|
|
2017-08-09 01:51:52 +00:00
|
|
|
lovrGraphicsSetCullingEnabled(wasCulling);
|
|
|
|
glDepthMask(GL_TRUE);
|
2016-10-24 22:02:23 +00:00
|
|
|
lovrGraphicsPop();
|
|
|
|
}
|
2017-02-03 23:16:30 +00:00
|
|
|
|
2017-03-16 03:12:56 +00:00
|
|
|
void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign) {
|
2017-08-08 08:36:29 +00:00
|
|
|
Font* font = lovrGraphicsGetFont();
|
2017-08-02 02:58:24 +00:00
|
|
|
float scale = 1 / font->pixelDensity;
|
|
|
|
float offsety;
|
2017-08-09 01:57:41 +00:00
|
|
|
lovrFontRender(font, str, wrap, halign, valign, &state.streamData, &offsety);
|
2017-08-02 02:58:24 +00:00
|
|
|
|
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsMatrixTransform(transform);
|
|
|
|
lovrGraphicsScale(scale, scale, scale);
|
|
|
|
lovrGraphicsTranslate(0, offsety, 0);
|
|
|
|
lovrGraphicsBindTexture(font->texture);
|
2017-08-09 04:02:28 +00:00
|
|
|
lovrGraphicsSetDefaultShader(SHADER_FONT);
|
2017-08-02 02:58:24 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 0, 1, 0);
|
|
|
|
lovrGraphicsPop();
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
2017-08-08 09:13:07 +00:00
|
|
|
|
|
|
|
// Internal State
|
2017-08-08 09:20:55 +00:00
|
|
|
void lovrGraphicsPushCanvas() {
|
|
|
|
if (++state.canvas >= MAX_CANVASES) {
|
|
|
|
error("Canvas overflow");
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&state.canvases[state.canvas], &state.canvases[state.canvas - 1], sizeof(CanvasState));
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsPopCanvas() {
|
|
|
|
if (--state.canvas < 0) {
|
|
|
|
error("Canvas underflow");
|
|
|
|
}
|
|
|
|
|
|
|
|
int* viewport = state.canvases[state.canvas].viewport;
|
|
|
|
lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
|
|
|
lovrGraphicsBindFramebuffer(state.canvases[state.canvas].framebuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
mat4 lovrGraphicsGetProjection() {
|
|
|
|
return state.canvases[state.canvas].projection;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetProjection(mat4 projection) {
|
|
|
|
memcpy(state.canvases[state.canvas].projection, projection, 16 * sizeof(float));
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetViewport(int x, int y, int w, int h) {
|
|
|
|
state.canvases[state.canvas].viewport[0] = x;
|
|
|
|
state.canvases[state.canvas].viewport[1] = y;
|
|
|
|
state.canvases[state.canvas].viewport[2] = w;
|
|
|
|
state.canvases[state.canvas].viewport[3] = h;
|
|
|
|
glViewport(x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsBindFramebuffer(int framebuffer) {
|
|
|
|
if (state.canvases[state.canvas].framebuffer != framebuffer) {
|
|
|
|
state.canvases[state.canvas].framebuffer = framebuffer;
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-08 09:14:50 +00:00
|
|
|
Texture* lovrGraphicsGetTexture() {
|
|
|
|
return state.texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsBindTexture(Texture* texture) {
|
|
|
|
if (!texture) {
|
2017-08-09 04:02:28 +00:00
|
|
|
if (!state.defaultTexture) {
|
|
|
|
state.defaultTexture = lovrTextureCreate(lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA));
|
|
|
|
}
|
|
|
|
|
2017-08-08 09:14:50 +00:00
|
|
|
texture = state.defaultTexture;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (texture != state.texture) {
|
|
|
|
state.texture = texture;
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-09 07:56:13 +00:00
|
|
|
void lovrGraphicsSetDefaultShader(DefaultShader shader) {
|
|
|
|
state.defaultShader = shader;
|
|
|
|
}
|
|
|
|
|
|
|
|
Shader* lovrGraphicsGetActiveShader() {
|
|
|
|
return state.shader ? state.shader : state.defaultShaders[state.defaultShader];
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsBindProgram(uint32_t program) {
|
|
|
|
if (state.program != program) {
|
|
|
|
state.program = program;
|
|
|
|
glUseProgram(program);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-08 09:13:07 +00:00
|
|
|
void lovrGraphicsBindVertexArray(uint32_t vertexArray) {
|
|
|
|
if (state.vertexArray != vertexArray) {
|
|
|
|
state.vertexArray = vertexArray;
|
|
|
|
glBindVertexArray(vertexArray);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsBindVertexBuffer(uint32_t vertexBuffer) {
|
|
|
|
if (state.vertexBuffer != vertexBuffer) {
|
|
|
|
state.vertexBuffer = vertexBuffer;
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsBindIndexBuffer(uint32_t indexBuffer) {
|
|
|
|
if (state.indexBuffer != indexBuffer) {
|
|
|
|
state.indexBuffer = indexBuffer;
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
|
|
|
|
}
|
|
|
|
}
|