2016-11-19 09:28:01 +00:00
|
|
|
#include "graphics/graphics.h"
|
2018-07-04 20:51:35 +00:00
|
|
|
#include "data/modelData.h"
|
2018-02-11 23:22:04 +00:00
|
|
|
#include "data/textureData.h"
|
2018-01-22 16:28:33 +00:00
|
|
|
#include "data/rasterizer.h"
|
2017-12-10 20:31:50 +00:00
|
|
|
#include "resources/shaders.h"
|
2017-04-13 02:48:17 +00:00
|
|
|
#include "event/event.h"
|
2017-11-26 01:57:59 +00:00
|
|
|
#include "math/math.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>
|
2018-07-04 20:51:35 +00:00
|
|
|
#include <string.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;
|
2018-01-27 03:01:20 +00:00
|
|
|
EventData data = { .quit = { false, 0 } };
|
2017-04-13 02:48:17 +00:00
|
|
|
Event event = { .type = type, .data = data };
|
|
|
|
lovrEventPush(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-26 01:57:59 +00:00
|
|
|
static void gammaCorrectColor(Color* color) {
|
|
|
|
if (state.gammaCorrect) {
|
|
|
|
color->r = lovrMathGammaToLinear(color->r);
|
|
|
|
color->g = lovrMathGammaToLinear(color->g);
|
|
|
|
color->b = lovrMathGammaToLinear(color->b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-05 03:11:52 +00:00
|
|
|
static GLenum convertCompareMode(CompareMode mode) {
|
|
|
|
switch (mode) {
|
|
|
|
case COMPARE_NONE: return GL_ALWAYS;
|
|
|
|
case COMPARE_EQUAL: return GL_EQUAL;
|
|
|
|
case COMPARE_NEQUAL: return GL_NOTEQUAL;
|
|
|
|
case COMPARE_LESS: return GL_LESS;
|
|
|
|
case COMPARE_LEQUAL: return GL_LEQUAL;
|
|
|
|
case COMPARE_GREATER: return GL_GREATER;
|
|
|
|
case COMPARE_GEQUAL: return GL_GEQUAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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() {
|
2018-02-23 03:18:36 +00:00
|
|
|
if (!state.initialized) return;
|
2016-11-19 22:06:41 +00:00
|
|
|
lovrGraphicsSetShader(NULL);
|
2017-08-09 00:53:03 +00:00
|
|
|
lovrGraphicsSetFont(NULL);
|
2018-03-24 02:31:32 +00:00
|
|
|
lovrGraphicsSetCanvas(NULL, 0);
|
2017-08-09 04:02:28 +00:00
|
|
|
for (int i = 0; i < DEFAULT_SHADER_COUNT; i++) {
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRelease(state.defaultShaders[i]);
|
2017-08-09 04:02:28 +00:00
|
|
|
}
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRelease(state.defaultMaterial);
|
|
|
|
lovrRelease(state.defaultFont);
|
2018-03-22 05:03:03 +00:00
|
|
|
lovrRelease(state.mesh);
|
2018-07-11 23:43:31 +00:00
|
|
|
gpuDestroy();
|
2018-02-23 03:18:36 +00:00
|
|
|
memset(&state, 0, sizeof(GraphicsState));
|
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();
|
2016-11-27 18:57:36 +00:00
|
|
|
state.transform = 0;
|
2018-03-05 05:51:53 +00:00
|
|
|
state.layer = 0;
|
2018-06-05 02:49:36 +00:00
|
|
|
memcpy(state.layers[state.layer].viewport, (int[]) { 0, 0, w, h }, 4 * sizeof(uint32_t));
|
2018-06-04 00:18:42 +00:00
|
|
|
mat4_perspective(state.layers[state.layer].projection, .01f, 100.f, 67 * M_PI / 180., (float) w / h);
|
|
|
|
mat4_identity(state.layers[state.layer].view);
|
2017-11-21 05:47:25 +00:00
|
|
|
lovrGraphicsSetBackgroundColor((Color) { 0, 0, 0, 1. });
|
2017-04-01 22:33:32 +00:00
|
|
|
lovrGraphicsSetBlendMode(BLEND_ALPHA, BLEND_ALPHA_MULTIPLY);
|
2018-06-12 01:59:09 +00:00
|
|
|
lovrGraphicsSetCanvas(NULL, 0);
|
2017-11-21 05:47:25 +00:00
|
|
|
lovrGraphicsSetColor((Color) { 1., 1., 1., 1. });
|
2017-10-31 08:14:09 +00:00
|
|
|
lovrGraphicsSetCullingEnabled(false);
|
2017-08-09 05:39:00 +00:00
|
|
|
lovrGraphicsSetDefaultFilter((TextureFilter) { .mode = FILTER_TRILINEAR });
|
2018-02-09 05:50:47 +00:00
|
|
|
lovrGraphicsSetDepthTest(COMPARE_LEQUAL, true);
|
2017-08-09 05:39:00 +00:00
|
|
|
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-12-19 02:37:03 +00:00
|
|
|
lovrGraphicsSetStencilTest(COMPARE_NONE, 0);
|
2017-08-02 07:54:33 +00:00
|
|
|
lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE);
|
2017-10-31 08:14:09 +00:00
|
|
|
lovrGraphicsSetWireframe(false);
|
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
|
|
|
|
2018-02-09 05:26:53 +00:00
|
|
|
void lovrGraphicsClear(bool clearColor, bool clearDepth, bool clearStencil, Color color, float depth, int stencil) {
|
2018-03-22 16:40:35 +00:00
|
|
|
Layer layer = state.layers[state.layer];
|
2018-07-13 20:53:55 +00:00
|
|
|
gpuBindFramebuffer(layer.canvasCount > 0 ? lovrCanvasGetId(layer.canvas[0]) : 0);
|
2018-03-22 16:40:35 +00:00
|
|
|
|
2018-02-09 05:26:53 +00:00
|
|
|
if (clearColor) {
|
2018-03-11 04:59:36 +00:00
|
|
|
gammaCorrectColor(&color);
|
2018-02-09 05:26:53 +00:00
|
|
|
float c[4] = { color.r, color.g, color.b, color.a };
|
|
|
|
glClearBufferfv(GL_COLOR, 0, c);
|
2018-07-13 20:53:55 +00:00
|
|
|
for (int i = 1; i < layer.canvasCount; i++) {
|
2018-02-15 08:37:02 +00:00
|
|
|
glClearBufferfv(GL_COLOR, i, c);
|
|
|
|
}
|
2018-02-09 05:26:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (clearDepth) {
|
|
|
|
glClearBufferfv(GL_DEPTH, 0, &depth);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clearStencil) {
|
|
|
|
glClearBufferiv(GL_STENCIL, 0, &stencil);
|
|
|
|
}
|
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);
|
2018-07-07 23:54:07 +00:00
|
|
|
gpuPresent();
|
2016-07-07 07:04:24 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
void lovrGraphicsCreateWindow(int w, int h, bool fullscreen, int msaa, const char* title, const char* icon) {
|
2018-02-23 03:18:36 +00:00
|
|
|
lovrAssert(!state.window, "Window is already created");
|
|
|
|
|
2018-05-13 06:58:38 +00:00
|
|
|
#ifndef EMSCRIPTEN
|
2018-02-23 09:28:42 +00:00
|
|
|
if ((state.window = glfwGetCurrentContext()) == NULL) {
|
|
|
|
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);
|
|
|
|
glfwWindowHint(GLFW_SRGB_CAPABLE, state.gammaCorrect);
|
2018-05-13 06:58:38 +00:00
|
|
|
#else
|
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
|
|
|
glfwWindowHint(GLFW_SAMPLES, msaa);
|
|
|
|
glfwWindowHint(GLFW_SRGB_CAPABLE, state.gammaCorrect);
|
2017-08-10 03:02:02 +00:00
|
|
|
#endif
|
|
|
|
|
2018-02-23 09:28:42 +00:00
|
|
|
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);
|
|
|
|
}
|
2017-08-10 03:02:02 +00:00
|
|
|
|
2018-02-23 09:28:42 +00:00
|
|
|
state.window = glfwCreateWindow(w ? w : mode->width, h ? h : mode->height, title, fullscreen ? monitor : NULL, NULL);
|
|
|
|
if (!state.window) {
|
|
|
|
glfwTerminate();
|
|
|
|
lovrThrow("Could not create window");
|
|
|
|
}
|
2017-08-10 03:02:02 +00:00
|
|
|
|
2018-02-23 09:28:42 +00:00
|
|
|
if (icon) {
|
|
|
|
GLFWimage image;
|
|
|
|
image.pixels = stbi_load(icon, &image.width, &image.height, NULL, 3);
|
|
|
|
glfwSetWindowIcon(state.window, 1, &image);
|
|
|
|
free(image.pixels);
|
|
|
|
}
|
2017-08-10 03:02:02 +00:00
|
|
|
|
2018-02-23 09:28:42 +00:00
|
|
|
glfwMakeContextCurrent(state.window);
|
|
|
|
glfwSetWindowCloseCallback(state.window, onCloseWindow);
|
2018-05-13 06:58:38 +00:00
|
|
|
#ifndef EMSCRIPTEN
|
2018-02-23 09:28:42 +00:00
|
|
|
}
|
2017-08-10 03:02:02 +00:00
|
|
|
|
|
|
|
glfwSwapInterval(0);
|
2017-11-23 22:19:20 +00:00
|
|
|
#endif
|
2018-07-07 23:54:07 +00:00
|
|
|
gpuInit(state.gammaCorrect, glfwGetProcAddress);
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexFormat format;
|
|
|
|
vertexFormatInit(&format);
|
|
|
|
vertexFormatAppend(&format, "lovrPosition", ATTR_FLOAT, 3);
|
|
|
|
vertexFormatAppend(&format, "lovrNormal", ATTR_FLOAT, 3);
|
|
|
|
vertexFormatAppend(&format, "lovrTexCoord", ATTR_FLOAT, 2);
|
|
|
|
state.mesh = lovrMeshCreate(64, format, MESH_TRIANGLES, MESH_STREAM);
|
2017-08-10 03:02:02 +00:00
|
|
|
lovrGraphicsReset();
|
2018-02-23 03:18:36 +00:00
|
|
|
state.initialized = true;
|
2017-08-10 03:02:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int lovrGraphicsGetWidth() {
|
|
|
|
int width, height;
|
|
|
|
glfwGetFramebufferSize(state.window, &width, &height);
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lovrGraphicsGetHeight() {
|
|
|
|
int width, height;
|
|
|
|
glfwGetFramebufferSize(state.window, &width, &height);
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
2018-07-12 02:31:11 +00:00
|
|
|
GpuStats lovrGraphicsGetStats() {
|
|
|
|
return gpuGetStats();
|
2017-12-10 04:07:32 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2017-11-26 01:57:59 +00:00
|
|
|
gammaCorrectColor(&color);
|
2017-11-21 05:47:25 +00:00
|
|
|
glClearColor(color.r, color.g, color.b, color.a);
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-15 08:37:02 +00:00
|
|
|
void lovrGraphicsGetCanvas(Canvas** canvas, int* count) {
|
2018-07-13 20:53:55 +00:00
|
|
|
Layer layer = state.layers[state.layer];
|
|
|
|
if (layer.user) {
|
|
|
|
*count = layer.canvasCount;
|
|
|
|
memcpy(canvas, layer.canvas, layer.canvasCount * sizeof(Canvas*));
|
|
|
|
} else {
|
|
|
|
*count = 0;
|
|
|
|
}
|
2018-02-15 08:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetCanvas(Canvas** canvas, int count) {
|
2018-07-13 20:53:55 +00:00
|
|
|
if (state.layers[state.layer].user) {
|
|
|
|
lovrGraphicsPopLayer();
|
2018-02-15 08:37:02 +00:00
|
|
|
}
|
|
|
|
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsPushLayer(canvas, count, true);
|
2018-02-15 08:37:02 +00:00
|
|
|
}
|
|
|
|
|
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-10-31 08:14:09 +00:00
|
|
|
bool lovrGraphicsIsCullingEnabled() {
|
2017-08-02 07:54:33 +00:00
|
|
|
return state.culling;
|
2016-09-14 00:02:23 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
void lovrGraphicsSetCullingEnabled(bool culling) {
|
2017-08-02 07:54:33 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-02-09 05:50:47 +00:00
|
|
|
void lovrGraphicsGetDepthTest(CompareMode* mode, bool* write) {
|
|
|
|
*mode = state.depthTest;
|
|
|
|
*write = state.depthWrite;
|
2017-02-17 08:48:43 +00:00
|
|
|
}
|
|
|
|
|
2018-07-05 03:11:52 +00:00
|
|
|
void lovrGraphicsSetDepthTest(CompareMode mode, bool write) {
|
|
|
|
if (state.depthTest != mode) {
|
|
|
|
state.depthTest = mode;
|
|
|
|
if (mode != COMPARE_NONE) {
|
|
|
|
glDepthFunc(convertCompareMode(mode));
|
2017-08-02 07:54:33 +00:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
}
|
2017-02-06 04:30:17 +00:00
|
|
|
}
|
2018-02-09 05:50:47 +00:00
|
|
|
|
|
|
|
if (state.depthWrite != write) {
|
|
|
|
state.depthWrite = write;
|
|
|
|
glDepthMask(write);
|
|
|
|
}
|
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) {
|
2018-01-22 16:28:33 +00:00
|
|
|
Rasterizer* rasterizer = lovrRasterizerCreate(NULL, 32);
|
|
|
|
state.defaultFont = lovrFontCreate(rasterizer);
|
2018-03-24 02:31:32 +00:00
|
|
|
lovrRelease(rasterizer);
|
2017-08-09 06:49:17 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 08:36:29 +00:00
|
|
|
lovrGraphicsSetFont(state.defaultFont);
|
|
|
|
}
|
|
|
|
|
|
|
|
return state.font;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetFont(Font* font) {
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRetain(font);
|
|
|
|
lovrRelease(state.font);
|
2017-08-08 08:36:29 +00:00
|
|
|
state.font = font;
|
|
|
|
}
|
|
|
|
|
2017-11-23 04:26:01 +00:00
|
|
|
bool lovrGraphicsIsGammaCorrect() {
|
|
|
|
return state.gammaCorrect;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetGammaCorrect(bool gammaCorrect) {
|
|
|
|
state.gammaCorrect = gammaCorrect;
|
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
GraphicsLimits lovrGraphicsGetLimits() {
|
|
|
|
if (!state.limits.initialized) {
|
2017-08-15 07:36:09 +00:00
|
|
|
#ifdef EMSCRIPTEN
|
2017-10-22 23:26:48 +00:00
|
|
|
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, state.limits.pointSizes);
|
2017-08-15 07:36:09 +00:00
|
|
|
#else
|
2017-08-02 07:54:33 +00:00
|
|
|
glGetFloatv(GL_POINT_SIZE_RANGE, state.limits.pointSizes);
|
2017-08-15 07:36:09 +00:00
|
|
|
#endif
|
2017-08-02 07:54:33 +00:00
|
|
|
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-06-18 04:09:03 +00:00
|
|
|
state.pointSize = size;
|
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) {
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRetain(shader);
|
|
|
|
lovrRelease(state.shader);
|
2017-08-08 08:32:15 +00:00
|
|
|
state.shader = shader;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-19 02:37:03 +00:00
|
|
|
void lovrGraphicsGetStencilTest(CompareMode* mode, int* value) {
|
|
|
|
*mode = state.stencilMode;
|
|
|
|
*value = state.stencilValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetStencilTest(CompareMode mode, int value) {
|
2017-12-19 03:48:28 +00:00
|
|
|
state.stencilMode = mode;
|
|
|
|
state.stencilValue = value;
|
|
|
|
|
|
|
|
if (state.stencilWriting) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode != COMPARE_NONE) {
|
|
|
|
if (!state.stencilEnabled) {
|
2017-12-19 02:37:03 +00:00
|
|
|
glEnable(GL_STENCIL_TEST);
|
2017-12-19 03:48:28 +00:00
|
|
|
state.stencilEnabled = true;
|
|
|
|
}
|
2017-12-19 02:37:03 +00:00
|
|
|
|
2018-07-05 03:11:52 +00:00
|
|
|
GLenum glMode = GL_ALWAYS;
|
2017-12-19 03:48:28 +00:00
|
|
|
switch (mode) {
|
2018-07-05 03:11:52 +00:00
|
|
|
case COMPARE_EQUAL: glMode = GL_EQUAL; break;
|
|
|
|
case COMPARE_NEQUAL: glMode = GL_NOTEQUAL; break;
|
2017-12-19 03:48:28 +00:00
|
|
|
case COMPARE_LESS: glMode = GL_GREATER; break;
|
|
|
|
case COMPARE_LEQUAL: glMode = GL_GEQUAL; break;
|
|
|
|
case COMPARE_GREATER: glMode = GL_LESS; break;
|
2018-07-05 03:11:52 +00:00
|
|
|
case COMPARE_GEQUAL: glMode = GL_LEQUAL; break;
|
2017-12-19 03:48:28 +00:00
|
|
|
default: break;
|
2017-12-19 02:37:03 +00:00
|
|
|
}
|
2017-12-19 03:48:28 +00:00
|
|
|
|
|
|
|
glStencilFunc(glMode, value, 0xff);
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
|
|
} else if (state.stencilEnabled) {
|
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
state.stencilEnabled = false;
|
2017-12-19 02:37:03 +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) {
|
2018-02-26 10:10:53 +00:00
|
|
|
if (winding != state.winding) {
|
|
|
|
state.winding = winding;
|
2018-07-05 03:11:52 +00:00
|
|
|
GLenum glWinding = winding == WINDING_CLOCKWISE ? GL_CW : GL_CCW;
|
|
|
|
glFrontFace(glWinding);
|
2018-02-26 10:10:53 +00:00
|
|
|
}
|
2016-10-03 19:02:49 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
bool lovrGraphicsIsWireframe() {
|
2017-08-02 07:54:33 +00:00
|
|
|
return state.wireframe;
|
2016-10-03 19:02:49 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
void lovrGraphicsSetWireframe(bool wireframe) {
|
2017-08-02 07:54:33 +00:00
|
|
|
#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
|
|
|
|
|
2017-08-10 08:05:04 +00:00
|
|
|
void lovrGraphicsPush() {
|
|
|
|
if (++state.transform >= MAX_TRANSFORMS) {
|
|
|
|
lovrThrow("Unbalanced matrix stack (more pushes than pops?)");
|
|
|
|
}
|
|
|
|
|
2017-08-11 05:23:19 +00:00
|
|
|
memcpy(state.transforms[state.transform], state.transforms[state.transform - 1], 2 * 16 * sizeof(float));
|
2016-09-21 07:55:53 +00:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:05:04 +00:00
|
|
|
void lovrGraphicsPop() {
|
|
|
|
if (--state.transform < 0) {
|
|
|
|
lovrThrow("Unbalanced matrix stack (more pops than pushes?)");
|
|
|
|
}
|
2016-09-21 07:55:53 +00:00
|
|
|
}
|
|
|
|
|
2016-09-21 22:26:05 +00:00
|
|
|
void lovrGraphicsOrigin() {
|
2018-03-05 07:06:34 +00:00
|
|
|
mat4_identity(state.transforms[state.transform]);
|
2016-09-21 22:26:05 +00:00
|
|
|
}
|
|
|
|
|
2018-03-05 07:06:34 +00:00
|
|
|
void lovrGraphicsTranslate(float x, float y, float z) {
|
|
|
|
mat4_translate(state.transforms[state.transform], x, y, z);
|
2016-09-23 04:53:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-05 07:06:34 +00:00
|
|
|
void lovrGraphicsRotate(float angle, float ax, float ay, float az) {
|
|
|
|
mat4_rotate(state.transforms[state.transform], angle, ax, ay, az);
|
2016-09-23 04:53:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-05 07:06:34 +00:00
|
|
|
void lovrGraphicsScale(float x, float y, float z) {
|
|
|
|
mat4_scale(state.transforms[state.transform], x, y, z);
|
2016-09-23 04:53:17 +00:00
|
|
|
}
|
|
|
|
|
2018-03-05 07:06:34 +00:00
|
|
|
void lovrGraphicsMatrixTransform(mat4 transform) {
|
|
|
|
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
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer lovrGraphicsGetVertexPointer(uint32_t count) {
|
2018-06-04 02:00:31 +00:00
|
|
|
lovrMeshResize(state.mesh, count);
|
|
|
|
return lovrMeshMapVertices(state.mesh, 0, count, false, true);
|
2016-09-30 02:39:25 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
void lovrGraphicsPoints(uint32_t count) {
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_POINTS);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, count);
|
|
|
|
lovrMeshSetMaterial(state.mesh, NULL);
|
|
|
|
lovrMeshWriteIndices(state.mesh, 0, 0);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_DEFAULT, 1);
|
2016-11-08 07:16:33 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
void lovrGraphicsLine(uint32_t count) {
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_LINE_STRIP);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, count);
|
|
|
|
lovrMeshSetMaterial(state.mesh, NULL);
|
|
|
|
lovrMeshWriteIndices(state.mesh, 0, 0);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_DEFAULT, 1);
|
2016-09-29 07:00:02 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
void lovrGraphicsTriangle(DrawMode mode, Material* material, float points[9]) {
|
2016-11-23 04:43:22 +00:00
|
|
|
if (mode == DRAW_MODE_LINE) {
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(3);
|
|
|
|
|
|
|
|
float vertices[24] = {
|
|
|
|
points[0], points[1], points[2], 0, 0, 0, 0, 0,
|
|
|
|
points[3], points[4], points[5], 0, 0, 0, 0, 0,
|
|
|
|
points[6], points[7], points[8], 0, 0, 0, 0, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
memcpy(vertexPointer.raw, vertices, 3 * 8 * sizeof(float));
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_LINE_LOOP);
|
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
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
float vertices[24] = {
|
|
|
|
points[0], points[1], points[2], normal[0], normal[1], normal[2], 0, 0,
|
|
|
|
points[3], points[4], points[5], normal[0], normal[1], normal[2], 0, 0,
|
|
|
|
points[6], points[7], points[8], normal[0], normal[1], normal[2], 0, 0
|
2016-11-23 04:43:22 +00:00
|
|
|
};
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(3);
|
|
|
|
memcpy(vertexPointer.raw, vertices, 3 * 8 * sizeof(float));
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLES);
|
2016-11-23 04:43:22 +00:00
|
|
|
}
|
2018-03-22 05:03:03 +00:00
|
|
|
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, 3);
|
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_DEFAULT, 1);
|
2016-11-23 04:43:22 +00:00
|
|
|
}
|
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
void lovrGraphicsPlane(DrawMode mode, Material* material, mat4 transform) {
|
2016-10-04 03:56:45 +00:00
|
|
|
if (mode == DRAW_MODE_LINE) {
|
2018-03-22 05:03:03 +00:00
|
|
|
float vertices[] = {
|
|
|
|
-.5, .5, 0, 0, 0, 0, 0, 0,
|
|
|
|
.5, .5, 0, 0, 0, 0, 0, 0,
|
|
|
|
.5, -.5, 0, 0, 0, 0, 0, 0,
|
|
|
|
-.5, -.5, 0, 0, 0, 0, 0, 0
|
2016-10-07 06:34:35 +00:00
|
|
|
};
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(4);
|
|
|
|
memcpy(vertexPointer.raw, vertices, 4 * 8 * sizeof(float));
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_LINE_LOOP);
|
2016-10-04 03:56:45 +00:00
|
|
|
} else if (mode == DRAW_MODE_FILL) {
|
2018-03-22 05:03:03 +00:00
|
|
|
float vertices[] = {
|
2017-12-10 03:11:53 +00:00
|
|
|
-.5, .5, 0, 0, 0, -1, 0, 1,
|
|
|
|
-.5, -.5, 0, 0, 0, -1, 0, 0,
|
|
|
|
.5, .5, 0, 0, 0, -1, 1, 1,
|
|
|
|
.5, -.5, 0, 0, 0, -1, 1, 0
|
2016-10-07 06:34:35 +00:00
|
|
|
};
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(4);
|
|
|
|
memcpy(vertexPointer.raw, vertices, 4 * 8 * sizeof(float));
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLE_STRIP);
|
2016-10-04 03:56:45 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
|
|
|
lovrMeshWriteIndices(state.mesh, 0, 0);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, 4);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsMatrixTransform(transform);
|
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_DEFAULT, 1);
|
|
|
|
lovrGraphicsPop();
|
2016-10-04 03:56:45 +00:00
|
|
|
}
|
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
void lovrGraphicsBox(DrawMode mode, Material* material, mat4 transform) {
|
2016-10-01 19:53:15 +00:00
|
|
|
if (mode == DRAW_MODE_LINE) {
|
2018-03-22 05:03:03 +00:00
|
|
|
float vertices[] = {
|
2016-10-07 06:34:35 +00:00
|
|
|
// Front
|
2018-03-22 05:03:03 +00:00
|
|
|
-.5, .5, -.5, 0, 0, 0, 0, 0,
|
|
|
|
.5, .5, -.5, 0, 0, 0, 0, 0,
|
|
|
|
.5, -.5, -.5, 0, 0, 0, 0, 0,
|
|
|
|
-.5, -.5, -.5, 0, 0, 0, 0, 0,
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
// Back
|
2018-03-22 05:03:03 +00:00
|
|
|
-.5, .5, .5, 0, 0, 0, 0, 0,
|
|
|
|
.5, .5, .5, 0, 0, 0, 0, 0,
|
|
|
|
.5, -.5, .5, 0, 0, 0, 0, 0,
|
|
|
|
-.5, -.5, .5, 0, 0, 0, 0, 0
|
2016-10-07 06:34:35 +00:00
|
|
|
};
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
uint16_t 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
|
|
|
|
};
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(8);
|
|
|
|
memcpy(vertexPointer.raw, vertices, 8 * 8 * sizeof(float));
|
|
|
|
IndexPointer indexPointer = lovrMeshWriteIndices(state.mesh, 24, sizeof(uint16_t));
|
|
|
|
memcpy(indexPointer.shorts, indices, 24 * sizeof(uint16_t));
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_LINES);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, 24);
|
2016-10-01 19:10:38 +00:00
|
|
|
} else {
|
2018-03-22 05:03:03 +00:00
|
|
|
float vertices[] = {
|
2016-10-07 06:34:35 +00:00
|
|
|
// Front
|
2017-01-15 21:49:24 +00:00
|
|
|
-.5, -.5, -.5, 0, 0, -1, 0, 0,
|
|
|
|
-.5, .5, -.5, 0, 0, -1, 0, 1,
|
2018-03-04 01:19:12 +00:00
|
|
|
.5, -.5, -.5, 0, 0, -1, 1, 0,
|
2017-01-15 21:49:24 +00:00
|
|
|
.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, 1, 1,
|
2018-03-04 01:19:12 +00:00
|
|
|
.5, -.5, -.5, 1, 0, 0, 0, 0,
|
2017-01-15 21:49:24 +00:00
|
|
|
.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, 0, 1,
|
2018-03-04 01:19:12 +00:00
|
|
|
-.5, -.5, .5, 0, 0, 1, 1, 0,
|
2017-01-15 21:49:24 +00:00
|
|
|
-.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, 1, 1,
|
2018-03-04 01:19:12 +00:00
|
|
|
-.5, -.5, .5, -1, 0, 0, 0, 0,
|
2017-01-15 21:49:24 +00:00
|
|
|
-.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, 1, 0,
|
2018-03-04 01:19:12 +00:00
|
|
|
-.5, -.5, .5, 0, -1, 0, 0, 1,
|
2017-01-15 21:49:24 +00:00
|
|
|
.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, 0, 0,
|
2018-03-04 01:19:12 +00:00
|
|
|
.5, .5, -.5, 0, 1, 0, 1, 1,
|
2017-01-15 21:49:24 +00:00
|
|
|
.5, .5, .5, 0, 1, 0, 1, 0
|
2016-10-01 19:53:15 +00:00
|
|
|
};
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(26);
|
|
|
|
memcpy(vertexPointer.floats, vertices, 26 * 8 * sizeof(float));
|
|
|
|
lovrMeshWriteIndices(state.mesh, 0, 0);
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLE_STRIP);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, 26);
|
2016-10-01 19:10:38 +00:00
|
|
|
}
|
2016-10-01 19:53:15 +00:00
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsMatrixTransform(transform);
|
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_DEFAULT, 1);
|
|
|
|
lovrGraphicsPop();
|
2016-09-30 06:18:51 +00:00
|
|
|
}
|
2016-10-24 22:02:23 +00:00
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
void lovrGraphicsArc(DrawMode mode, ArcMode arcMode, Material* material, mat4 transform, float theta1, float theta2, int segments) {
|
2017-11-22 19:32:30 +00:00
|
|
|
if (fabsf(theta1 - theta2) >= 2 * M_PI) {
|
|
|
|
theta1 = 0;
|
|
|
|
theta2 = 2 * M_PI;
|
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
bool hasCenterPoint = arcMode == ARC_MODE_PIE && fabsf(theta1 - theta2) < 2 * M_PI;
|
|
|
|
uint32_t count = segments + 1 + hasCenterPoint;
|
2017-11-22 04:53:34 +00:00
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertices = lovrGraphicsGetVertexPointer(count);
|
2017-11-22 19:32:30 +00:00
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
if (hasCenterPoint) {
|
|
|
|
*vertices.floats++ = 0;
|
|
|
|
*vertices.floats++ = 0;
|
|
|
|
*vertices.floats++ = 0;
|
|
|
|
*vertices.floats++ = 0;
|
|
|
|
*vertices.floats++ = 0;
|
|
|
|
*vertices.floats++ = 1;
|
|
|
|
*vertices.floats++ = .5;
|
|
|
|
*vertices.floats++ = .5;
|
2017-11-22 19:32:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float theta = theta1;
|
|
|
|
float angleShift = (theta2 - theta1) / (float) segments;
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
for (int i = 0; i <= segments; i++) {
|
|
|
|
float x = cos(theta) * .5;
|
|
|
|
float y = sin(theta) * .5;
|
|
|
|
|
|
|
|
*vertices.floats++ = x;
|
|
|
|
*vertices.floats++ = y;
|
|
|
|
*vertices.floats++ = 0;
|
|
|
|
*vertices.floats++ = 0;
|
|
|
|
*vertices.floats++ = 0;
|
|
|
|
*vertices.floats++ = 1;
|
|
|
|
*vertices.floats++ = x + .5;
|
|
|
|
*vertices.floats++ = 1 - (y + .5);
|
|
|
|
|
|
|
|
theta += angleShift;
|
2017-11-22 04:53:34 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
|
|
|
lovrMeshSetDrawMode(state.mesh, mode == DRAW_MODE_LINE ? (arcMode == ARC_MODE_OPEN ? MESH_LINE_STRIP : MESH_LINE_LOOP) : MESH_TRIANGLE_FAN);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, count);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsMatrixTransform(transform);
|
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_DEFAULT, 1);
|
|
|
|
lovrGraphicsPop();
|
2017-11-22 04:53:34 +00:00
|
|
|
}
|
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
void lovrGraphicsCircle(DrawMode mode, Material* material, mat4 transform, int segments) {
|
|
|
|
lovrGraphicsArc(mode, ARC_MODE_OPEN, material, transform, 0, 2 * M_PI, segments);
|
2017-11-22 19:32:30 +00:00
|
|
|
}
|
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, float x2, float y2, float z2, float r1, float r2, bool capped, int segments) {
|
2017-06-21 03:54:22 +00:00
|
|
|
float axis[3] = { x1 - x2, y1 - y2, z1 - z2 };
|
|
|
|
float n[3] = { x1 - x2, y1 - y2, z1 - z2 };
|
|
|
|
float p[3];
|
|
|
|
float q[3];
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
uint32_t vertexCount = ((capped && r1) * (segments + 2) + (capped && r2) * (segments + 2) + 2 * (segments + 1));
|
|
|
|
uint32_t indexCount = 3 * segments * ((capped && r1) + (capped && r2) + 2);
|
2017-06-21 03:54:22 +00:00
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertices = lovrGraphicsGetVertexPointer(vertexCount);
|
|
|
|
IndexPointer indices = lovrMeshWriteIndices(state.mesh, indexCount, sizeof(uint32_t));
|
|
|
|
float* baseVertex = vertices.floats;
|
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) \
|
2018-03-22 05:03:03 +00:00
|
|
|
*vertices.floats++ = x; \
|
|
|
|
*vertices.floats++ = y; \
|
|
|
|
*vertices.floats++ = z; \
|
|
|
|
*vertices.floats++ = nx; \
|
|
|
|
*vertices.floats++ = ny; \
|
|
|
|
*vertices.floats++ = nz; \
|
|
|
|
*vertices.floats++ = 0; \
|
|
|
|
*vertices.floats++ = 0;
|
2017-06-21 03:54:22 +00:00
|
|
|
#define PUSH_CYLINDER_TRIANGLE(i1, i2, i3) \
|
2018-03-22 05:03:03 +00:00
|
|
|
*indices.ints++ = i1; \
|
|
|
|
*indices.ints++ = i2; \
|
|
|
|
*indices.ints++ = i3; \
|
2017-06-21 03:54:22 +00:00
|
|
|
|
|
|
|
// Ring
|
|
|
|
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
|
2018-03-22 05:03:03 +00:00
|
|
|
int topOffset = (segments + 1) * 2;
|
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++) {
|
2018-03-22 05:03:03 +00:00
|
|
|
int j = i * 2 * 8;
|
|
|
|
PUSH_CYLINDER_VERTEX(baseVertex[j + 0], baseVertex[j + 1], baseVertex[j + 2], axis[0], axis[1], axis[2]);
|
2017-06-21 03:54:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bottom
|
2018-03-22 05:03:03 +00:00
|
|
|
int bottomOffset = (segments + 1) * 2 + (1 + segments + 1) * (capped && r1 != 0);
|
2017-06-21 03:54:22 +00:00
|
|
|
if (capped && r2 != 0) {
|
2018-03-22 05:03:03 +00:00
|
|
|
PUSH_CYLINDER_VERTEX(x2, y2, z1, -axis[0], -axis[1], -axis[2]);
|
2017-06-21 03:54:22 +00:00
|
|
|
for (int i = 0; i <= segments; i++) {
|
2018-03-22 05:03:03 +00:00
|
|
|
int j = i * 2 * 8 + 8;
|
|
|
|
PUSH_CYLINDER_VERTEX(baseVertex[j + 0], baseVertex[j + 1], baseVertex[j + 2], -axis[0], -axis[1], -axis[2]);
|
2017-06-21 03:54:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Indices
|
|
|
|
for (int i = 0; i < segments; i++) {
|
2018-03-22 05:03:03 +00:00
|
|
|
int j = 2 * i;
|
2017-06-21 03:54:22 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#undef PUSH_CYLINDER_VERTEX
|
|
|
|
#undef PUSH_CYLINDER_TRIANGLE
|
2018-03-22 05:03:03 +00:00
|
|
|
|
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLES);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, indexCount);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_DEFAULT, 1);
|
2017-06-21 03:54:22 +00:00
|
|
|
}
|
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
void lovrGraphicsSphere(Material* material, mat4 transform, int segments) {
|
2018-03-22 05:03:03 +00:00
|
|
|
VertexPointer vertices = lovrGraphicsGetVertexPointer((segments + 1) * (segments + 1));
|
|
|
|
IndexPointer indices = lovrMeshWriteIndices(state.mesh, segments * segments * 6, sizeof(uint32_t));
|
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;
|
|
|
|
|
2017-08-16 04:21:49 +00:00
|
|
|
float x = sin(u * 2 * M_PI) * sin(v * M_PI);
|
2017-06-22 06:10:45 +00:00
|
|
|
float y = cos(v * M_PI);
|
2017-08-16 04:21:49 +00:00
|
|
|
float z = -cos(u * 2 * M_PI) * sin(v * M_PI);
|
2017-06-22 06:10:45 +00:00
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
*vertices.floats++ = x;
|
|
|
|
*vertices.floats++ = y;
|
|
|
|
*vertices.floats++ = z;
|
|
|
|
*vertices.floats++ = x;
|
|
|
|
*vertices.floats++ = y;
|
|
|
|
*vertices.floats++ = z;
|
|
|
|
*vertices.floats++ = u;
|
|
|
|
*vertices.floats++ = 1 - 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;
|
2018-03-22 05:03:03 +00:00
|
|
|
*indices.ints++ = index0;
|
|
|
|
*indices.ints++ = index1;
|
|
|
|
*indices.ints++ = index0 + 1;
|
|
|
|
*indices.ints++ = index1;
|
|
|
|
*indices.ints++ = index1 + 1;
|
|
|
|
*indices.ints++ = index0 + 1;
|
2017-06-22 06:10:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
lovrMeshSetDrawMode(state.mesh, GL_TRIANGLES);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, segments * segments * 6);
|
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsMatrixTransform(transform);
|
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_DEFAULT, 1);
|
|
|
|
lovrGraphicsPop();
|
2017-06-22 06:10:45 +00:00
|
|
|
}
|
|
|
|
|
2017-10-15 23:56:00 +00:00
|
|
|
void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float az) {
|
2018-03-05 10:02:25 +00:00
|
|
|
float vertices[] = {
|
|
|
|
-1, 1, 1, 0, 0, 0, 0, 0,
|
|
|
|
-1, -1, 1, 0, 0, 0, 0, 0,
|
|
|
|
1, 1, 1, 0, 0, 0, 0, 0,
|
|
|
|
1, -1, 1, 0, 0, 0, 0, 0
|
|
|
|
};
|
2018-02-26 10:10:53 +00:00
|
|
|
|
2018-07-09 07:51:09 +00:00
|
|
|
TextureType type = lovrTextureGetType(texture);
|
2018-03-05 10:02:25 +00:00
|
|
|
lovrAssert(type == TEXTURE_CUBE || type == TEXTURE_2D, "Only 2D and cube textures can be used as skyboxes");
|
|
|
|
MaterialTexture materialTexture = type == TEXTURE_CUBE ? TEXTURE_ENVIRONMENT_MAP : TEXTURE_DIFFUSE;
|
2018-03-22 15:45:05 +00:00
|
|
|
DefaultShader shader = type == TEXTURE_CUBE ? SHADER_CUBE : SHADER_PANO;
|
2018-03-05 10:02:25 +00:00
|
|
|
Winding winding = state.winding;
|
2018-02-26 10:10:53 +00:00
|
|
|
lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE);
|
2018-03-05 10:02:25 +00:00
|
|
|
Material* material = lovrGraphicsGetDefaultMaterial();
|
|
|
|
lovrMaterialSetTexture(material, materialTexture, texture);
|
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(4);
|
|
|
|
memcpy(vertexPointer.raw, vertices, 4 * 8 * sizeof(float));
|
|
|
|
lovrMeshWriteIndices(state.mesh, 0, 0);
|
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLE_STRIP);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, 4);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsDraw(state.mesh, shader, 1);
|
2018-03-05 10:02:25 +00:00
|
|
|
lovrMaterialSetTexture(material, materialTexture, NULL);
|
2018-02-26 10:10:53 +00:00
|
|
|
lovrGraphicsSetWinding(winding);
|
2016-10-24 22:02:23 +00:00
|
|
|
}
|
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;
|
2018-03-22 05:03:03 +00:00
|
|
|
uint32_t vertexCount;
|
|
|
|
uint32_t maxVertices = strlen(str) * 6;
|
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(maxVertices);
|
|
|
|
lovrFontRender(font, str, wrap, halign, valign, vertexPointer, &offsety, &vertexCount);
|
|
|
|
lovrMeshWriteIndices(state.mesh, 0, 0);
|
2017-08-02 02:58:24 +00:00
|
|
|
|
|
|
|
lovrGraphicsPush();
|
2018-03-05 07:06:34 +00:00
|
|
|
lovrGraphicsMatrixTransform(transform);
|
|
|
|
lovrGraphicsScale(scale, scale, scale);
|
|
|
|
lovrGraphicsTranslate(0, offsety, 0);
|
2017-11-26 03:02:28 +00:00
|
|
|
Material* material = lovrGraphicsGetDefaultMaterial();
|
2017-10-21 21:59:34 +00:00
|
|
|
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, font->texture);
|
2018-02-09 05:50:47 +00:00
|
|
|
CompareMode mode;
|
|
|
|
bool write;
|
|
|
|
lovrGraphicsGetDepthTest(&mode, &write);
|
|
|
|
lovrGraphicsSetDepthTest(mode, false);
|
2018-03-22 05:03:03 +00:00
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLES);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, vertexCount);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_FONT, 1);
|
2018-02-09 05:50:47 +00:00
|
|
|
lovrGraphicsSetDepthTest(mode, write);
|
2017-11-26 03:02:28 +00:00
|
|
|
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL);
|
2017-08-02 02:58:24 +00:00
|
|
|
lovrGraphicsPop();
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
2017-08-08 09:13:07 +00:00
|
|
|
|
2017-12-19 03:48:28 +00:00
|
|
|
void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata) {
|
2018-02-09 05:50:47 +00:00
|
|
|
CompareMode mode;
|
|
|
|
bool write;
|
|
|
|
lovrGraphicsGetDepthTest(&mode, &write);
|
|
|
|
lovrGraphicsSetDepthTest(mode, false);
|
2017-12-19 03:48:28 +00:00
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
|
|
|
|
|
|
if (!state.stencilEnabled) {
|
|
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
state.stencilEnabled = true;
|
|
|
|
}
|
|
|
|
|
2018-07-05 03:11:52 +00:00
|
|
|
GLenum glAction;
|
|
|
|
switch (action) {
|
|
|
|
case STENCIL_REPLACE: glAction = GL_REPLACE; break;
|
|
|
|
case STENCIL_INCREMENT: glAction = GL_INCR; break;
|
|
|
|
case STENCIL_DECREMENT: glAction = GL_DECR; break;
|
|
|
|
case STENCIL_INCREMENT_WRAP: glAction = GL_INCR_WRAP; break;
|
|
|
|
case STENCIL_DECREMENT_WRAP: glAction = GL_DECR_WRAP; break;
|
|
|
|
case STENCIL_INVERT: glAction = GL_INVERT; break;
|
|
|
|
}
|
|
|
|
|
2017-12-19 03:48:28 +00:00
|
|
|
glStencilFunc(GL_ALWAYS, replaceValue, 0xff);
|
2018-07-05 03:11:52 +00:00
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, glAction);
|
2017-12-19 03:48:28 +00:00
|
|
|
|
|
|
|
state.stencilWriting = true;
|
|
|
|
callback(userdata);
|
|
|
|
state.stencilWriting = false;
|
|
|
|
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
2018-02-09 05:50:47 +00:00
|
|
|
lovrGraphicsSetDepthTest(mode, write);
|
2017-12-19 03:48:28 +00:00
|
|
|
lovrGraphicsSetStencilTest(state.stencilMode, state.stencilValue);
|
|
|
|
}
|
|
|
|
|
2018-03-19 19:12:34 +00:00
|
|
|
void lovrGraphicsFill(Texture* texture) {
|
2018-03-11 07:18:07 +00:00
|
|
|
float vertices[] = {
|
|
|
|
-1, 1, 0, 0, 0, 0, 0, 1,
|
|
|
|
-1, -1, 0, 0, 0, 0, 0, 0,
|
|
|
|
1, 1, 0, 0, 0, 0, 1, 1,
|
|
|
|
1, -1, 0, 0, 0, 0, 1, 0
|
|
|
|
};
|
|
|
|
|
2018-03-19 19:47:35 +00:00
|
|
|
CompareMode mode;
|
|
|
|
bool write;
|
|
|
|
lovrGraphicsGetDepthTest(&mode, &write);
|
|
|
|
lovrGraphicsSetDepthTest(COMPARE_NONE, false);
|
2018-03-11 07:18:07 +00:00
|
|
|
Material* material = lovrGraphicsGetDefaultMaterial();
|
|
|
|
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture);
|
|
|
|
VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(4);
|
|
|
|
memcpy(vertexPointer.raw, vertices, 4 * 8 * sizeof(float));
|
|
|
|
lovrMeshWriteIndices(state.mesh, 0, 0);
|
|
|
|
lovrMeshSetMaterial(state.mesh, material);
|
|
|
|
lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLE_STRIP);
|
|
|
|
lovrMeshSetDrawRange(state.mesh, 0, 4);
|
2018-07-13 20:53:55 +00:00
|
|
|
lovrGraphicsDraw(state.mesh, SHADER_FILL, 1);
|
2018-03-22 16:40:35 +00:00
|
|
|
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL);
|
2018-03-19 19:47:35 +00:00
|
|
|
lovrGraphicsSetDepthTest(mode, write);
|
2018-03-11 07:18:07 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 15:45:05 +00:00
|
|
|
// Internal
|
2018-07-13 20:53:55 +00:00
|
|
|
void lovrGraphicsDraw(Mesh* mesh, DefaultShader defaultShader, int instances) {
|
2018-06-04 00:18:42 +00:00
|
|
|
Shader* shader = state.shader ? state.shader : state.defaultShaders[defaultShader];
|
|
|
|
|
|
|
|
if (!shader) {
|
|
|
|
shader = state.defaultShaders[defaultShader] = lovrShaderCreateDefault(defaultShader);
|
|
|
|
}
|
|
|
|
|
2018-03-22 15:45:05 +00:00
|
|
|
// Pose
|
|
|
|
float* pose = lovrMeshGetPose(mesh);
|
|
|
|
if (pose) {
|
|
|
|
lovrShaderSetMatrix(shader, "lovrPose", pose, MAX_BONES * 16);
|
|
|
|
} else {
|
|
|
|
float identity[16];
|
|
|
|
mat4_identity(identity);
|
|
|
|
lovrShaderSetMatrix(shader, "lovrPose", identity, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Material
|
|
|
|
Material* material = lovrMeshGetMaterial(mesh);
|
2018-07-13 20:53:55 +00:00
|
|
|
material = material ? material : lovrGraphicsGetDefaultMaterial();
|
2018-03-22 15:45:05 +00:00
|
|
|
|
2018-07-12 02:25:01 +00:00
|
|
|
gpuDraw(&(GpuDrawCommand) {
|
2018-07-13 20:53:55 +00:00
|
|
|
.layer = state.layers[state.layer],
|
2018-07-12 02:25:01 +00:00
|
|
|
.shader = shader,
|
2018-07-13 20:53:55 +00:00
|
|
|
.material = material,
|
|
|
|
.transform = state.transforms[state.transform],
|
|
|
|
.mesh = mesh,
|
|
|
|
.color = state.color,
|
|
|
|
.pointSize = state.pointSize,
|
2018-07-12 02:25:01 +00:00
|
|
|
.instances = instances
|
|
|
|
});
|
2018-07-13 20:53:55 +00:00
|
|
|
}
|
2018-03-22 15:45:05 +00:00
|
|
|
|
2018-07-13 20:53:55 +00:00
|
|
|
void lovrGraphicsPushLayer(Canvas** canvas, int count, bool user) {
|
|
|
|
lovrAssert(count <= MAX_CANVASES, "Attempt to set %d canvases (the maximum is %d)", count, MAX_CANVASES);
|
|
|
|
lovrAssert(++state.layer < MAX_LAYERS, "Layer overflow");
|
|
|
|
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
lovrRetain(canvas[i]);
|
2018-03-22 15:45:05 +00:00
|
|
|
}
|
|
|
|
|
2018-07-13 20:53:55 +00:00
|
|
|
Layer* prevLayer = &state.layers[state.layer - 1];
|
|
|
|
for (int i = 0; i < prevLayer->canvasCount; i++) {
|
|
|
|
lovrRelease(prevLayer->canvas[i]);
|
2017-08-08 09:20:55 +00:00
|
|
|
}
|
|
|
|
|
2018-07-13 20:53:55 +00:00
|
|
|
Layer* layer = &state.layers[state.layer];
|
|
|
|
memcpy(layer, prevLayer, sizeof(Layer));
|
|
|
|
layer->canvasCount = count;
|
|
|
|
layer->user = user;
|
|
|
|
|
|
|
|
if (count > 0) {
|
|
|
|
memcpy(layer->canvas, canvas, count * sizeof(Canvas*));
|
|
|
|
gpuBindFramebuffer(lovrCanvasGetId(canvas[0]));
|
|
|
|
|
|
|
|
GLenum buffers[MAX_CANVASES];
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
buffers[i] = GL_COLOR_ATTACHMENT0 + i;
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, buffers[i], GL_TEXTURE_2D, lovrTextureGetId((Texture*) canvas[i]), 0);
|
|
|
|
}
|
|
|
|
glDrawBuffers(count, buffers);
|
|
|
|
|
|
|
|
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
|
lovrAssert(status != GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS, "All multicanvas canvases must have the same dimensions");
|
|
|
|
lovrAssert(status == GL_FRAMEBUFFER_COMPLETE, "Unable to bind framebuffer");
|
|
|
|
}
|
2017-08-08 09:20:55 +00:00
|
|
|
}
|
|
|
|
|
2018-03-05 05:51:53 +00:00
|
|
|
void lovrGraphicsPopLayer() {
|
2018-07-13 20:53:55 +00:00
|
|
|
Layer* layer = &state.layers[state.layer];
|
|
|
|
if (layer->canvasCount > 0) {
|
|
|
|
lovrCanvasResolve(layer->canvas[0]);
|
2018-03-05 10:48:36 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 19:38:39 +00:00
|
|
|
lovrAssert(--state.layer >= 0, "Layer underflow");
|
2017-08-08 09:20:55 +00:00
|
|
|
}
|
|
|
|
|
2018-06-04 00:18:42 +00:00
|
|
|
void lovrGraphicsSetCamera(mat4 projection, mat4 view) {
|
|
|
|
mat4_set(state.layers[state.layer].projection, projection);
|
|
|
|
mat4_set(state.layers[state.layer].view, view);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
|
|
|
|
state.layers[state.layer].viewport[0] = x;
|
|
|
|
state.layers[state.layer].viewport[1] = y;
|
|
|
|
state.layers[state.layer].viewport[2] = width;
|
|
|
|
state.layers[state.layer].viewport[3] = height;
|
|
|
|
}
|
|
|
|
|
2017-11-26 03:02:28 +00:00
|
|
|
Material* lovrGraphicsGetDefaultMaterial() {
|
|
|
|
if (!state.defaultMaterial) {
|
2018-01-30 05:44:32 +00:00
|
|
|
state.defaultMaterial = lovrMaterialCreate(true);
|
2017-11-26 03:02:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return state.defaultMaterial;
|
|
|
|
}
|