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-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"
|
|
|
|
#include "glfw.h"
|
2016-09-27 07:24:28 +00:00
|
|
|
#define _USE_MATH_DEFINES
|
2016-07-16 05:39:17 +00:00
|
|
|
#include <stdlib.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
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
// Base
|
|
|
|
|
2016-08-10 06:28:17 +00:00
|
|
|
void lovrGraphicsInit() {
|
2017-01-12 04:26:08 +00:00
|
|
|
for (int i = 0; i < MAX_CANVASES; i++) {
|
|
|
|
state.canvases[i] = malloc(sizeof(CanvasState));
|
|
|
|
}
|
2016-10-04 04:54:27 +00:00
|
|
|
state.defaultShader = lovrShaderCreate(lovrDefaultVertexShader, lovrDefaultFragmentShader);
|
2016-10-24 22:02:23 +00:00
|
|
|
state.skyboxShader = lovrShaderCreate(lovrSkyboxVertexShader, lovrSkyboxFragmentShader);
|
2017-01-13 09:59:00 +00:00
|
|
|
state.fullscreenShader = lovrShaderCreate(lovrNoopVertexShader, lovrDefaultFragmentShader);
|
2016-11-27 02:58:58 +00:00
|
|
|
int uniformId = lovrShaderGetUniformId(state.skyboxShader, "cube");
|
|
|
|
lovrShaderSendInt(state.skyboxShader, uniformId, 1);
|
2017-01-12 07:38:28 +00:00
|
|
|
state.defaultTexture = lovrTextureCreate(lovrTextureDataGetBlank(1, 1, 0xff));
|
2016-09-29 07:00:02 +00:00
|
|
|
glGenBuffers(1, &state.shapeBuffer);
|
2016-09-30 06:18:51 +00:00
|
|
|
glGenBuffers(1, &state.shapeIndexBuffer);
|
2016-09-29 07:00:02 +00:00
|
|
|
glGenVertexArrays(1, &state.shapeArray);
|
|
|
|
vec_init(&state.shapeData);
|
2016-09-30 06:18:51 +00:00
|
|
|
vec_init(&state.shapeIndices);
|
2016-11-24 23:45:59 +00:00
|
|
|
state.depthTest = -1;
|
2016-09-28 03:20:08 +00:00
|
|
|
lovrGraphicsReset();
|
2017-01-22 02:18:12 +00:00
|
|
|
atexit(lovrGraphicsDestroy);
|
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);
|
|
|
|
glUseProgram(0);
|
2017-01-12 04:26:08 +00:00
|
|
|
for (int i = 0; i < MAX_CANVASES; i++) {
|
|
|
|
free(state.canvases[i]);
|
|
|
|
}
|
2016-11-19 22:06:41 +00:00
|
|
|
lovrRelease(&state.defaultShader->ref);
|
|
|
|
lovrRelease(&state.skyboxShader->ref);
|
2017-01-13 09:59:00 +00:00
|
|
|
lovrRelease(&state.fullscreenShader->ref);
|
2016-11-27 02:58:58 +00:00
|
|
|
lovrRelease(&state.defaultTexture->ref);
|
2016-10-04 22:13:57 +00:00
|
|
|
glDeleteBuffers(1, &state.shapeBuffer);
|
|
|
|
glDeleteBuffers(1, &state.shapeIndexBuffer);
|
|
|
|
glDeleteVertexArrays(1, &state.shapeArray);
|
|
|
|
vec_deinit(&state.shapeData);
|
|
|
|
vec_deinit(&state.shapeIndices);
|
|
|
|
}
|
|
|
|
|
2016-09-28 03:20:08 +00:00
|
|
|
void lovrGraphicsReset() {
|
2016-11-27 18:57:36 +00:00
|
|
|
state.transform = 0;
|
2017-01-11 17:22:18 +00:00
|
|
|
state.canvas = 0;
|
2017-01-12 04:26:08 +00:00
|
|
|
lovrGraphicsSetViewport(0, 0, lovrGraphicsGetWidth(), lovrGraphicsGetHeight());
|
2016-09-29 03:11:58 +00:00
|
|
|
lovrGraphicsSetProjection(.1f, 100.f, 67 * M_PI / 180); // TODO customize via lovr.conf
|
2017-01-12 04:26:08 +00:00
|
|
|
lovrGraphicsBindFramebuffer(0);
|
2016-11-27 10:06:47 +00:00
|
|
|
lovrGraphicsSetShader(NULL);
|
|
|
|
lovrGraphicsBindTexture(NULL);
|
2016-09-29 03:11:58 +00:00
|
|
|
lovrGraphicsSetBackgroundColor(0, 0, 0, 0);
|
|
|
|
lovrGraphicsSetColor(255, 255, 255, 255);
|
2016-09-28 04:32:57 +00:00
|
|
|
lovrGraphicsSetColorMask(1, 1, 1, 1);
|
2016-09-29 04:47:36 +00:00
|
|
|
lovrGraphicsSetScissorEnabled(0);
|
2016-10-01 20:48:31 +00:00
|
|
|
lovrGraphicsSetLineWidth(1);
|
2016-11-13 01:38:49 +00:00
|
|
|
lovrGraphicsSetPointSize(1);
|
2016-10-03 19:02:49 +00:00
|
|
|
lovrGraphicsSetCullingEnabled(0);
|
|
|
|
lovrGraphicsSetPolygonWinding(POLYGON_WINDING_COUNTERCLOCKWISE);
|
2016-11-23 04:59:11 +00:00
|
|
|
lovrGraphicsSetDepthTest(COMPARE_LESS);
|
2016-11-23 05:07:33 +00:00
|
|
|
lovrGraphicsSetWireframe(0);
|
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) {
|
|
|
|
int bits = 0;
|
|
|
|
|
|
|
|
if (color) {
|
|
|
|
bits |= GL_COLOR_BUFFER_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (depth) {
|
|
|
|
bits |= GL_DEPTH_BUFFER_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
glClear(bits);
|
2016-07-07 07:04:24 +00:00
|
|
|
}
|
|
|
|
|
2016-08-10 06:28:17 +00:00
|
|
|
void lovrGraphicsPresent() {
|
2016-07-07 07:04:24 +00:00
|
|
|
glfwSwapBuffers(window);
|
|
|
|
}
|
|
|
|
|
2016-09-24 03:58:56 +00:00
|
|
|
void lovrGraphicsPrepare() {
|
|
|
|
Shader* shader = lovrGraphicsGetShader();
|
2017-01-11 17:22:18 +00:00
|
|
|
mat4 transform = state.transforms[state.transform];
|
2017-01-12 04:26:08 +00:00
|
|
|
mat4 projection = state.canvases[state.canvas]->projection;
|
2017-01-11 17:22:18 +00:00
|
|
|
lovrShaderBind(shader, transform, projection, state.color, 0);
|
2016-09-24 03:58:56 +00:00
|
|
|
}
|
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
// State
|
|
|
|
|
2016-09-28 04:37:46 +00:00
|
|
|
void lovrGraphicsGetBackgroundColor(float* r, float* g, float* b, float* a) {
|
2016-07-28 02:48:59 +00:00
|
|
|
GLfloat clearColor[4];
|
|
|
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
|
2016-08-10 06:28:17 +00:00
|
|
|
*r = clearColor[0];
|
|
|
|
*g = clearColor[1];
|
|
|
|
*b = clearColor[2];
|
|
|
|
*a = clearColor[3];
|
2016-07-28 02:48:59 +00:00
|
|
|
}
|
|
|
|
|
2016-09-28 04:37:46 +00:00
|
|
|
void lovrGraphicsSetBackgroundColor(float r, float g, float b, float a) {
|
2016-08-08 20:51:22 +00:00
|
|
|
glClearColor(r / 255, g / 255, b / 255, a / 255);
|
2016-07-28 02:48:59 +00:00
|
|
|
}
|
|
|
|
|
2016-09-29 03:11:58 +00:00
|
|
|
void lovrGraphicsGetColor(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a) {
|
|
|
|
*r = LOVR_COLOR_R(state.color);
|
|
|
|
*g = LOVR_COLOR_G(state.color);
|
|
|
|
*b = LOVR_COLOR_B(state.color);
|
|
|
|
*a = LOVR_COLOR_A(state.color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
|
|
|
|
state.color = LOVR_COLOR(r, g, b, a);
|
|
|
|
}
|
|
|
|
|
2016-10-03 18:41:31 +00:00
|
|
|
void lovrGraphicsGetColorMask(char* r, char* g, char* b, char* a) {
|
|
|
|
char mask = state.colorMask;
|
2016-09-28 04:32:57 +00:00
|
|
|
*r = mask & 0x1;
|
|
|
|
*g = mask & 0x2;
|
|
|
|
*b = mask & 0x4;
|
|
|
|
*a = mask & 0x8;
|
|
|
|
}
|
|
|
|
|
2016-10-03 18:41:31 +00:00
|
|
|
void lovrGraphicsSetColorMask(char r, char g, char b, char a) {
|
2016-09-28 04:32:57 +00:00
|
|
|
state.colorMask = ((r & 1) << 0) | ((g & 1) << 1) | ((b & 1) << 2) | ((a & 1) << 3);
|
|
|
|
glColorMask(r, g, b, a);
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:07:33 +00:00
|
|
|
int lovrGraphicsIsScissorEnabled() {
|
2016-09-29 04:47:36 +00:00
|
|
|
return state.isScissorEnabled;
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:07:33 +00:00
|
|
|
void lovrGraphicsSetScissorEnabled(int isEnabled) {
|
2016-09-29 04:47:36 +00:00
|
|
|
state.isScissorEnabled = isEnabled;
|
|
|
|
if (isEnabled) {
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsGetScissor(int* x, int* y, int* width, int* height) {
|
|
|
|
*x = state.scissor.x;
|
|
|
|
*y = state.scissor.x;
|
|
|
|
*width = state.scissor.width;
|
|
|
|
*height = state.scissor.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetScissor(int x, int y, int width, int height) {
|
|
|
|
int windowWidth, windowHeight;
|
2016-09-29 05:09:57 +00:00
|
|
|
glfwGetFramebufferSize(window, &windowWidth, &windowHeight);
|
2016-09-29 04:47:36 +00:00
|
|
|
state.scissor.x = x;
|
|
|
|
state.scissor.x = y;
|
|
|
|
state.scissor.width = width;
|
|
|
|
state.scissor.height = height;
|
|
|
|
glScissor(x, windowHeight - y, width, height);
|
|
|
|
}
|
|
|
|
|
2016-09-14 00:02:23 +00:00
|
|
|
Shader* lovrGraphicsGetShader() {
|
2016-09-27 06:48:09 +00:00
|
|
|
return state.activeShader;
|
2016-09-14 00:02:23 +00:00
|
|
|
}
|
|
|
|
|
2016-08-10 06:28:17 +00:00
|
|
|
void lovrGraphicsSetShader(Shader* shader) {
|
2016-09-28 02:56:36 +00:00
|
|
|
if (!shader) {
|
|
|
|
shader = state.defaultShader;
|
|
|
|
}
|
|
|
|
|
2016-11-19 22:06:41 +00:00
|
|
|
if (shader != state.activeShader) {
|
|
|
|
if (state.activeShader) {
|
|
|
|
lovrRelease(&state.activeShader->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
state.activeShader = shader;
|
|
|
|
lovrRetain(&state.activeShader->ref);
|
|
|
|
}
|
2016-07-16 02:17:27 +00:00
|
|
|
}
|
|
|
|
|
2016-11-27 10:06:47 +00:00
|
|
|
void lovrGraphicsBindTexture(Texture* texture) {
|
2016-11-27 02:58:58 +00:00
|
|
|
if (!texture) {
|
|
|
|
texture = state.defaultTexture;
|
|
|
|
}
|
|
|
|
|
2016-11-27 10:06:47 +00:00
|
|
|
lovrTextureBind(texture);
|
2016-11-27 02:58:58 +00:00
|
|
|
}
|
|
|
|
|
2017-01-12 09:26:44 +00:00
|
|
|
mat4 lovrGraphicsGetProjection() {
|
|
|
|
return state.canvases[state.canvas]->projection;
|
|
|
|
}
|
|
|
|
|
2016-09-27 06:48:09 +00:00
|
|
|
void lovrGraphicsSetProjection(float near, float far, float fov) {
|
|
|
|
int width, height;
|
|
|
|
glfwGetWindowSize(window, &width, &height);
|
2017-01-18 08:51:09 +00:00
|
|
|
mat4_perspective(state.canvases[state.canvas]->projection, near, far, fov, (float) width / height);
|
2017-01-12 04:26:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetProjectionRaw(mat4 projection) {
|
|
|
|
memcpy(state.canvases[state.canvas]->projection, projection, 16 * sizeof(float));
|
2016-09-27 07:24:28 +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) {
|
|
|
|
state.pointSize = size;
|
|
|
|
glPointSize(size);
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:07:33 +00:00
|
|
|
int lovrGraphicsIsCullingEnabled() {
|
2016-10-03 19:02:49 +00:00
|
|
|
return state.isCullingEnabled;
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:07:33 +00:00
|
|
|
void lovrGraphicsSetCullingEnabled(int isEnabled) {
|
2016-10-03 19:02:49 +00:00
|
|
|
state.isCullingEnabled = isEnabled;
|
|
|
|
if (isEnabled) {
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PolygonWinding lovrGraphicsGetPolygonWinding() {
|
|
|
|
return state.polygonWinding;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetPolygonWinding(PolygonWinding winding) {
|
|
|
|
state.polygonWinding = winding;
|
|
|
|
glFrontFace(winding);
|
|
|
|
}
|
|
|
|
|
2016-11-23 04:59:11 +00:00
|
|
|
CompareMode lovrGraphicsGetDepthTest() {
|
|
|
|
return state.depthTest;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetDepthTest(CompareMode depthTest) {
|
|
|
|
if (state.depthTest != depthTest) {
|
|
|
|
state.depthTest = depthTest;
|
|
|
|
glDepthFunc(depthTest);
|
2016-11-24 23:45:59 +00:00
|
|
|
if (depthTest) {
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
}
|
2016-11-23 04:59:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:07:33 +00:00
|
|
|
int lovrGraphicsIsWireframe() {
|
|
|
|
return state.isWireframe;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetWireframe(int wireframe) {
|
|
|
|
if (state.isWireframe != wireframe) {
|
|
|
|
state.isWireframe = wireframe;
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
int lovrGraphicsGetWidth() {
|
|
|
|
int width;
|
|
|
|
glfwGetFramebufferSize(window, &width, NULL);
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lovrGraphicsGetHeight() {
|
|
|
|
int height;
|
|
|
|
glfwGetFramebufferSize(window, NULL, &height);
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
2017-01-12 04:26:08 +00:00
|
|
|
void lovrGraphicsPushCanvas() {
|
|
|
|
if (++state.canvas >= MAX_CANVASES) {
|
2017-01-11 17:22:18 +00:00
|
|
|
error("Canvas overflow");
|
|
|
|
}
|
|
|
|
|
2017-01-12 04:26:08 +00:00
|
|
|
memcpy(state.canvases[state.canvas], state.canvases[state.canvas - 1], sizeof(CanvasState));
|
2017-01-11 17:22:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsPopCanvas() {
|
|
|
|
if (--state.canvas < 0) {
|
|
|
|
error("Canvas underflow");
|
|
|
|
}
|
|
|
|
|
2017-01-12 04:26:08 +00:00
|
|
|
int* viewport = state.canvases[state.canvas]->viewport;
|
|
|
|
lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
|
|
|
lovrGraphicsBindFramebuffer(state.canvases[state.canvas]->framebuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
state.canvases[state.canvas]->framebuffer = framebuffer;
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
2017-01-11 17:22:18 +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-01-13 09:59:00 +00:00
|
|
|
void lovrGraphicsDrawPrimitive(GLenum mode, Texture* texture, int hasNormals, int hasTexCoords, int useIndices) {
|
|
|
|
int stride = 3 + (hasNormals ? 3 : 0) + (hasTexCoords ? 2 : 0);
|
|
|
|
int strideBytes = stride * sizeof(float);
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
lovrGraphicsPrepare();
|
2017-01-13 09:59:00 +00:00
|
|
|
lovrGraphicsBindTexture(texture);
|
2016-09-29 07:00:02 +00:00
|
|
|
glBindVertexArray(state.shapeArray);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, state.shapeBuffer);
|
2017-01-13 09:59:00 +00:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, state.shapeData.length * sizeof(float), state.shapeData.data, GL_STREAM_DRAW);
|
|
|
|
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) {
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state.shapeIndexBuffer);
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, state.shapeIndices.length * sizeof(unsigned int), state.shapeIndices.data, GL_STREAM_DRAW);
|
|
|
|
glDrawElements(mode, state.shapeIndices.length, GL_UNSIGNED_INT, NULL);
|
|
|
|
} else {
|
|
|
|
glDrawArrays(mode, 0, state.shapeData.length / stride);
|
|
|
|
}
|
2016-10-07 06:34:35 +00:00
|
|
|
|
|
|
|
glBindVertexArray(0);
|
2016-09-30 02:39:25 +00:00
|
|
|
}
|
|
|
|
|
2016-11-08 07:16:33 +00:00
|
|
|
void lovrGraphicsPoints(float* points, int count) {
|
2017-01-13 09:59:00 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, points, count);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_POINTS, NULL, 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-01-13 09:59:00 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, points, count);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_LINE_STRIP, NULL, 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) {
|
|
|
|
if (mode == DRAW_MODE_LINE) {
|
2017-01-13 09:59:00 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, points, 9);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, NULL, 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-01-13 09:59:00 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, data, 18);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, NULL, 1, 0, 0);
|
2016-11-23 04:43:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-13 09:59:00 +00:00
|
|
|
void lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float z, float size, float nx, float ny, float nz) {
|
2016-10-04 03:56:45 +00:00
|
|
|
|
|
|
|
// Normalize the normal vector
|
|
|
|
float len = sqrt(nx * nx + ny * ny + nz + nz);
|
2017-01-20 02:50:51 +00:00
|
|
|
if (len != 0) {
|
2016-10-04 03:56:45 +00:00
|
|
|
len = 1 / len;
|
|
|
|
nx *= len;
|
|
|
|
ny *= len;
|
|
|
|
nz *= len;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vector perpendicular to the normal vector and the vector of the default geometry (cross product)
|
|
|
|
float cx = -ny;
|
|
|
|
float cy = nx;
|
|
|
|
float cz = 0.f;
|
|
|
|
|
|
|
|
// Angle between normal vector and the normal vector of the default geometry (dot product)
|
|
|
|
float theta = acos(nz);
|
|
|
|
|
2017-01-21 04:43:00 +00:00
|
|
|
float transform[16];
|
|
|
|
mat4_setTransform(transform, x, y, z, size, theta, cx, cy, cz);
|
|
|
|
|
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-01-13 09:59:00 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, points, 12);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, NULL, 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-01-13 09:59:00 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, data, 32);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, texture, 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
|
|
|
};
|
|
|
|
|
|
|
|
Shader* lastShader = lovrGraphicsGetShader();
|
|
|
|
lovrRetain(&lastShader->ref);
|
|
|
|
lovrGraphicsSetShader(state.fullscreenShader);
|
|
|
|
|
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, data, 20);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, texture, 0, 1, 0);
|
|
|
|
|
|
|
|
lovrGraphicsSetShader(lastShader);
|
|
|
|
lovrRelease(&lastShader->ref);
|
|
|
|
}
|
|
|
|
|
2017-01-20 03:11:42 +00:00
|
|
|
void lovrGraphicsCube(DrawMode mode, Texture* texture, mat4 transform) {
|
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-01-13 09:59:00 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, points, 24);
|
|
|
|
vec_clear(&state.shapeIndices);
|
|
|
|
vec_pusharr(&state.shapeIndices, indices, 24);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_LINES, NULL, 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-01-13 09:59:00 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, data, 208);
|
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, texture, 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
|
|
|
|
|
|
|
void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az) {
|
|
|
|
Shader* lastShader = lovrGraphicsGetShader();
|
2016-11-20 02:26:10 +00:00
|
|
|
lovrRetain(&lastShader->ref);
|
2016-10-24 22:02:23 +00:00
|
|
|
lovrGraphicsSetShader(state.skyboxShader);
|
|
|
|
|
|
|
|
lovrGraphicsPrepare();
|
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsOrigin();
|
2016-12-02 01:32:39 +00:00
|
|
|
lovrGraphicsRotate(angle, ax, ay, az);
|
2016-10-24 22:02:23 +00:00
|
|
|
|
|
|
|
float cube[] = {
|
|
|
|
// Front
|
2017-01-13 09:59:00 +00:00
|
|
|
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
|
|
|
|
|
|
|
// Left
|
2017-01-13 09:59:00 +00:00
|
|
|
-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
|
|
|
|
|
|
|
// Back
|
2017-01-13 09:59:00 +00:00
|
|
|
-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
|
|
|
|
|
|
|
// Right
|
2017-01-13 09:59:00 +00:00
|
|
|
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
|
|
|
|
|
|
|
// Bottom
|
2017-01-13 09:59:00 +00:00
|
|
|
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
|
|
|
|
|
|
|
// Adjust
|
2017-01-13 09:59:00 +00:00
|
|
|
-1.f, -1.f, 1.f,
|
|
|
|
-1.f, 1.f, -1.f,
|
2016-10-24 22:02:23 +00:00
|
|
|
|
|
|
|
// Top
|
2017-01-13 09:59:00 +00:00
|
|
|
-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-01-29 07:19:28 +00:00
|
|
|
vec_clear(&state.shapeData);
|
|
|
|
vec_pusharr(&state.shapeData, cube, 156);
|
|
|
|
|
2016-10-24 22:02:23 +00:00
|
|
|
glDepthMask(GL_FALSE);
|
2016-11-27 02:58:58 +00:00
|
|
|
glActiveTexture(GL_TEXTURE1);
|
2016-10-24 22:02:23 +00:00
|
|
|
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox->texture);
|
|
|
|
|
2017-01-29 07:19:28 +00:00
|
|
|
int wasCulling = lovrGraphicsIsCullingEnabled();
|
|
|
|
lovrGraphicsSetCullingEnabled(0);
|
2017-01-13 09:59:00 +00:00
|
|
|
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, NULL, 0, 0, 0);
|
2017-01-29 07:19:28 +00:00
|
|
|
lovrGraphicsSetCullingEnabled(wasCulling);
|
2016-10-24 22:02:23 +00:00
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
2017-01-29 07:19:28 +00:00
|
|
|
glActiveTexture(GL_TEXTURE0);
|
2016-10-24 22:02:23 +00:00
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
|
|
|
|
lovrGraphicsSetShader(lastShader);
|
2016-11-20 02:26:10 +00:00
|
|
|
lovrRelease(&lastShader->ref);
|
2016-10-24 22:02:23 +00:00
|
|
|
lovrGraphicsPop();
|
|
|
|
}
|