2016-11-19 09:28:01 +00:00
|
|
|
#include "graphics/graphics.h"
|
2018-01-22 16:28:33 +00:00
|
|
|
#include "data/rasterizer.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"
|
2016-11-19 09:28:01 +00:00
|
|
|
#include "util.h"
|
2018-11-15 16:03:51 +00:00
|
|
|
#include "lib/math.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
|
|
|
|
2018-11-16 10:26:56 +00:00
|
|
|
static void onCloseWindow() {
|
|
|
|
lovrEventPush((Event) { .type = EVENT_QUIT, .data.quit = { false, 0 } });
|
2017-04-13 02:48:17 +00:00
|
|
|
}
|
|
|
|
|
2018-11-16 10:26:56 +00:00
|
|
|
static void onResizeWindow(int width, int height) {
|
|
|
|
state.width = width;
|
|
|
|
state.height = height;
|
2017-11-26 01:57:59 +00:00
|
|
|
}
|
|
|
|
|
2018-12-25 02:44:38 +00:00
|
|
|
static bool batchable(DrawRequest* a) {
|
|
|
|
DrawRequest* b = &state.batch;
|
2018-12-12 06:10:29 +00:00
|
|
|
if (a->instances > 1) return false;
|
2018-12-11 21:27:59 +00:00
|
|
|
if (a->mesh != b->mesh) return false;
|
|
|
|
if (!a->mesh && a->mode != b->mode) return false;
|
|
|
|
if (!a->mesh && !!a->index.count != !!b->index.count) return false;
|
|
|
|
if (a->shader != b->shader) return false;
|
|
|
|
if (a->material != b->material) return false;
|
|
|
|
if (!a->material && a->diffuseTexture != b->diffuseTexture) return false;
|
|
|
|
if (!a->material && a->environmentMap != b->environmentMap) return false;
|
|
|
|
if (a->mono != b->mono) return false;
|
|
|
|
if (!!a->pose != !!b->pose || (a->pose && memcmp(a->pose, b->pose, MAX_BONES * 16 * sizeof(float)))) return false;
|
|
|
|
if (state.pipeline->dirty) return false;
|
2018-12-12 06:23:38 +00:00
|
|
|
if (a->mesh && lovrMeshIsDirty(a->mesh)) return false;
|
2018-12-11 21:27:59 +00:00
|
|
|
if (a->material && lovrMaterialIsDirty(a->material)) return false;
|
|
|
|
if (state.pipeline->shader && lovrShaderIsDirty(state.pipeline->shader)) return false;
|
|
|
|
if (state.pipeline->canvas && lovrCanvasIsDirty(state.pipeline->canvas)) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
// Base
|
|
|
|
|
2018-11-19 16:08:56 +00:00
|
|
|
bool lovrGraphicsInit(bool gammaCorrect) {
|
2018-08-23 19:51:53 +00:00
|
|
|
state.gammaCorrect = gammaCorrect;
|
2018-11-19 16:08:56 +00:00
|
|
|
return false;
|
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;
|
2018-12-11 21:27:59 +00:00
|
|
|
while (state.pipelineIndex > 0) {
|
2018-07-17 22:04:34 +00:00
|
|
|
lovrGraphicsPopPipeline();
|
2017-08-09 04:02:28 +00:00
|
|
|
}
|
2017-08-09 05:39:00 +00:00
|
|
|
lovrGraphicsSetShader(NULL);
|
2017-08-09 00:53:03 +00:00
|
|
|
lovrGraphicsSetFont(NULL);
|
2018-08-27 04:36:07 +00:00
|
|
|
lovrGraphicsSetCanvas(NULL);
|
2018-07-17 06:51:11 +00:00
|
|
|
for (int i = 0; i < MAX_DEFAULT_SHADERS; i++) {
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRelease(state.defaultShaders[i]);
|
2018-02-09 05:26:53 +00:00
|
|
|
}
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRelease(state.defaultMaterial);
|
|
|
|
lovrRelease(state.defaultFont);
|
2018-07-17 06:51:11 +00:00
|
|
|
lovrRelease(state.defaultMesh);
|
2018-12-11 05:30:55 +00:00
|
|
|
lovrRelease(state.vertexMap);
|
2018-12-12 06:10:29 +00:00
|
|
|
lovrRelease(state.identityBuffer);
|
2018-12-19 09:30:12 +00:00
|
|
|
lovrRelease(state.block);
|
2018-07-17 10:35:01 +00:00
|
|
|
lovrGpuDestroy();
|
2018-02-23 03:18:36 +00:00
|
|
|
memset(&state, 0, sizeof(GraphicsState));
|
2016-07-07 07:04:24 +00:00
|
|
|
}
|
|
|
|
|
2016-08-10 06:28:17 +00:00
|
|
|
void lovrGraphicsPresent() {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrGraphicsFlush();
|
2018-11-16 10:26:56 +00:00
|
|
|
lovrPlatformSwapBuffers();
|
2018-07-17 10:35:01 +00:00
|
|
|
lovrGpuPresent();
|
2016-07-07 07:04:24 +00:00
|
|
|
}
|
|
|
|
|
2018-11-16 10:26:56 +00:00
|
|
|
void lovrGraphicsSetWindow(WindowFlags* flags) {
|
|
|
|
lovrAssert(!state.initialized, "Window is already created");
|
2018-02-12 03:16:40 +00:00
|
|
|
|
2018-11-16 10:26:56 +00:00
|
|
|
if (flags) {
|
|
|
|
flags->srgb = state.gammaCorrect;
|
|
|
|
#ifdef EMSCRIPTEN
|
|
|
|
flags->vsync = 1;
|
2018-10-25 03:40:11 +00:00
|
|
|
#else
|
2018-11-16 10:26:56 +00:00
|
|
|
flags->vsync = 0;
|
2018-10-25 03:40:11 +00:00
|
|
|
#endif
|
2018-11-16 10:26:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lovrAssert(lovrPlatformSetWindow(flags), "Could not create window");
|
|
|
|
lovrPlatformOnWindowClose(onCloseWindow);
|
|
|
|
lovrPlatformOnWindowResize(onResizeWindow);
|
2018-11-16 11:18:08 +00:00
|
|
|
lovrPlatformGetFramebufferSize(&state.width, &state.height);
|
2018-11-16 10:26:56 +00:00
|
|
|
lovrGpuInit(state.gammaCorrect, lovrGetProcAddress);
|
2018-10-25 03:40:11 +00:00
|
|
|
|
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);
|
2018-12-13 02:43:04 +00:00
|
|
|
state.defaultMesh = lovrMeshCreate(MAX_VERTICES, format, DRAW_TRIANGLES, USAGE_STREAM, false);
|
2018-12-11 05:30:55 +00:00
|
|
|
|
|
|
|
state.vertexMap = lovrBufferCreate(MAX_VERTICES * sizeof(uint8_t), NULL, USAGE_STREAM, false);
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrMeshAttachAttribute(state.defaultMesh, "lovrDrawID", &(MeshAttribute) {
|
2018-12-11 05:30:55 +00:00
|
|
|
.buffer = state.vertexMap,
|
|
|
|
.type = ATTR_BYTE,
|
|
|
|
.components = 1,
|
|
|
|
.integer = true,
|
|
|
|
.enabled = true
|
|
|
|
});
|
2018-12-08 02:19:03 +00:00
|
|
|
|
|
|
|
vec_uniform_t uniforms;
|
|
|
|
vec_init(&uniforms);
|
2018-12-14 23:48:25 +00:00
|
|
|
vec_push(&uniforms, ((Uniform) { .name = "lovrModels", .type = UNIFORM_MATRIX, .components = 4, .count = MAX_BATCH_SIZE }));
|
|
|
|
vec_push(&uniforms, ((Uniform) { .name = "lovrColors", .type = UNIFORM_FLOAT, .components = 4, .count = MAX_BATCH_SIZE }));
|
2018-12-08 02:19:03 +00:00
|
|
|
state.block = lovrShaderBlockCreate(&uniforms, BLOCK_UNIFORM, USAGE_STREAM);
|
|
|
|
vec_deinit(&uniforms);
|
|
|
|
|
2018-12-12 06:10:29 +00:00
|
|
|
uint8_t identity[MAX_BATCH_SIZE];
|
|
|
|
for (int i = 0; i < MAX_BATCH_SIZE; i++) { identity[i] = i; }
|
|
|
|
state.identityBuffer = lovrBufferCreate(sizeof(identity), identity, USAGE_STATIC, false);
|
|
|
|
|
2017-08-10 03:02:02 +00:00
|
|
|
lovrGraphicsReset();
|
2018-02-23 03:18:36 +00:00
|
|
|
state.initialized = true;
|
2016-09-24 03:58:56 +00:00
|
|
|
}
|
|
|
|
|
2018-08-29 06:05:09 +00:00
|
|
|
int lovrGraphicsGetWidth() {
|
|
|
|
return state.width;
|
|
|
|
}
|
2018-10-20 19:22:24 +00:00
|
|
|
|
2018-08-29 06:05:09 +00:00
|
|
|
int lovrGraphicsGetHeight() {
|
|
|
|
return state.height;
|
2018-07-17 21:53:21 +00:00
|
|
|
}
|
2017-08-10 03:02:02 +00:00
|
|
|
|
2018-07-17 06:51:11 +00:00
|
|
|
void lovrGraphicsSetCamera(Camera* camera, bool clear) {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrGraphicsFlush();
|
|
|
|
|
2018-08-29 19:40:19 +00:00
|
|
|
if (state.camera.canvas && (!camera || camera->canvas != state.camera.canvas)) {
|
|
|
|
lovrCanvasResolve(state.camera.canvas);
|
2017-08-10 03:02:02 +00:00
|
|
|
}
|
|
|
|
|
2018-07-17 06:51:11 +00:00
|
|
|
if (!camera) {
|
|
|
|
state.camera.canvas = NULL;
|
2018-08-30 03:57:30 +00:00
|
|
|
state.camera.stereo = false;
|
2018-08-27 04:36:07 +00:00
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
mat4_identity(state.camera.viewMatrix[i]);
|
2018-08-29 06:05:09 +00:00
|
|
|
mat4_perspective(state.camera.projection[i], .01f, 100.f, 67 * M_PI / 180., (float) state.width / state.height);
|
2018-08-27 04:36:07 +00:00
|
|
|
}
|
2018-07-17 06:51:11 +00:00
|
|
|
} else {
|
|
|
|
state.camera = *camera;
|
2017-08-10 03:02:02 +00:00
|
|
|
}
|
|
|
|
|
2018-07-17 06:51:11 +00:00
|
|
|
if (clear) {
|
2018-12-25 02:53:23 +00:00
|
|
|
lovrGpuClear(state.camera.canvas, &state.backgroundColor, &(float) { 1. }, &(int) { 0 });
|
2017-08-10 03:02:02 +00:00
|
|
|
}
|
2018-07-17 06:51:11 +00:00
|
|
|
}
|
2017-08-10 03:02:02 +00:00
|
|
|
|
2018-12-12 06:10:29 +00:00
|
|
|
Buffer* lovrGraphicsGetIdentityBuffer() {
|
|
|
|
return state.identityBuffer;
|
|
|
|
}
|
|
|
|
|
2016-11-23 05:16:13 +00:00
|
|
|
// State
|
2017-08-10 03:02:02 +00:00
|
|
|
|
2018-07-16 00:05:06 +00:00
|
|
|
void lovrGraphicsReset() {
|
2018-12-11 21:27:59 +00:00
|
|
|
while (state.pipelineIndex > 0) {
|
2018-07-17 22:04:34 +00:00
|
|
|
lovrGraphicsPopPipeline();
|
2017-11-23 04:26:01 +00:00
|
|
|
}
|
2018-12-11 21:27:59 +00:00
|
|
|
state.pipeline = &state.pipelines[state.pipelineIndex];
|
2018-07-16 00:05:06 +00:00
|
|
|
state.transform = 0;
|
2018-07-17 06:51:11 +00:00
|
|
|
lovrGraphicsSetCamera(NULL, false);
|
|
|
|
lovrGraphicsSetBackgroundColor((Color) { 0, 0, 0, 1 });
|
2018-07-16 00:05:06 +00:00
|
|
|
lovrGraphicsSetBlendMode(BLEND_ALPHA, BLEND_ALPHA_MULTIPLY);
|
2018-08-27 04:36:07 +00:00
|
|
|
lovrGraphicsSetCanvas(NULL);
|
2018-07-17 06:51:11 +00:00
|
|
|
lovrGraphicsSetColor((Color) { 1, 1, 1, 1 });
|
2018-07-16 00:05:06 +00:00
|
|
|
lovrGraphicsSetCullingEnabled(false);
|
|
|
|
lovrGraphicsSetDefaultFilter((TextureFilter) { .mode = FILTER_TRILINEAR });
|
|
|
|
lovrGraphicsSetDepthTest(COMPARE_LEQUAL, true);
|
|
|
|
lovrGraphicsSetFont(NULL);
|
|
|
|
lovrGraphicsSetLineWidth(1);
|
|
|
|
lovrGraphicsSetPointSize(1);
|
|
|
|
lovrGraphicsSetShader(NULL);
|
|
|
|
lovrGraphicsSetStencilTest(COMPARE_NONE, 0);
|
|
|
|
lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE);
|
|
|
|
lovrGraphicsSetWireframe(false);
|
|
|
|
lovrGraphicsOrigin();
|
2017-08-10 03:02:02 +00:00
|
|
|
}
|
|
|
|
|
2018-07-17 06:51:11 +00:00
|
|
|
void lovrGraphicsPushPipeline() {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrAssert(++state.pipelineIndex < MAX_PIPELINES, "Unbalanced pipeline stack (more pushes than pops?)");
|
|
|
|
memcpy(&state.pipelines[state.pipelineIndex], &state.pipelines[state.pipelineIndex - 1], sizeof(Pipeline));
|
|
|
|
state.pipeline = &state.pipelines[state.pipelineIndex];
|
|
|
|
lovrRetain(state.pipeline->canvas);
|
|
|
|
lovrRetain(state.pipeline->font);
|
|
|
|
lovrRetain(state.pipeline->shader);
|
|
|
|
state.pipeline->dirty = true;
|
2017-08-10 03:02:02 +00:00
|
|
|
}
|
|
|
|
|
2018-07-17 06:51:11 +00:00
|
|
|
void lovrGraphicsPopPipeline() {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrRelease(state.pipeline->canvas);
|
|
|
|
lovrRelease(state.pipeline->font);
|
|
|
|
lovrRelease(state.pipeline->shader);
|
|
|
|
lovrAssert(--state.pipelineIndex >= 0, "Unbalanced pipeline stack (more pops than pushes?)");
|
|
|
|
state.pipeline = &state.pipelines[state.pipelineIndex];
|
2017-08-10 03:02:02 +00:00
|
|
|
}
|
|
|
|
|
2018-12-12 06:52:33 +00:00
|
|
|
bool lovrGraphicsGetAlphaSampling() {
|
|
|
|
return state.pipeline->alphaSampling;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetAlphaSampling(bool sample) {
|
|
|
|
if (state.pipeline->alphaSampling != sample) {
|
|
|
|
state.pipeline->alphaSampling = sample;
|
|
|
|
state.pipeline->dirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 08:25:56 +00:00
|
|
|
Color lovrGraphicsGetBackgroundColor() {
|
2018-12-25 02:53:23 +00:00
|
|
|
return state.backgroundColor;
|
2016-07-28 02:48:59 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 08:25:56 +00:00
|
|
|
void lovrGraphicsSetBackgroundColor(Color color) {
|
2018-12-25 02:53:23 +00:00
|
|
|
state.backgroundColor = color;
|
2016-07-28 02:48:59 +00:00
|
|
|
}
|
|
|
|
|
2017-03-12 11:03:36 +00:00
|
|
|
void lovrGraphicsGetBlendMode(BlendMode* mode, BlendAlphaMode* alphaMode) {
|
2018-12-11 21:27:59 +00:00
|
|
|
*mode = state.pipeline->blendMode;
|
|
|
|
*alphaMode = state.pipeline->blendAlphaMode;
|
2017-03-12 11:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetBlendMode(BlendMode mode, BlendAlphaMode alphaMode) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->blendMode != mode || state.pipeline->blendAlphaMode != alphaMode) {
|
|
|
|
state.pipeline->blendMode = mode;
|
|
|
|
state.pipeline->blendAlphaMode = alphaMode;
|
|
|
|
state.pipeline->dirty = true;
|
|
|
|
}
|
2017-03-12 11:03:36 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 04:08:40 +00:00
|
|
|
Canvas* lovrGraphicsGetCanvas() {
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->canvas;
|
2018-08-22 04:08:40 +00:00
|
|
|
}
|
2017-03-12 11:03:36 +00:00
|
|
|
|
2018-08-22 04:08:40 +00:00
|
|
|
void lovrGraphicsSetCanvas(Canvas* canvas) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->canvas != canvas) {
|
|
|
|
if (state.pipeline->canvas) {
|
|
|
|
lovrCanvasResolve(state.pipeline->canvas);
|
|
|
|
}
|
2018-08-29 19:40:19 +00:00
|
|
|
|
2018-12-11 21:27:59 +00:00
|
|
|
state.pipeline->canvas = canvas;
|
|
|
|
state.pipeline->dirty = true;
|
|
|
|
}
|
2017-03-12 11:03:36 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 08:25:56 +00:00
|
|
|
Color lovrGraphicsGetColor() {
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->color;
|
2016-09-29 03:11:58 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 08:25:56 +00:00
|
|
|
void lovrGraphicsSetColor(Color color) {
|
2018-12-11 21:27:59 +00:00
|
|
|
state.pipeline->color = color;
|
2016-09-29 03:11:58 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
bool lovrGraphicsIsCullingEnabled() {
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->culling;
|
2016-09-14 00:02:23 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
void lovrGraphicsSetCullingEnabled(bool culling) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->culling != culling) {
|
|
|
|
state.pipeline->culling = culling;
|
|
|
|
state.pipeline->dirty = true;
|
|
|
|
}
|
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) {
|
2018-12-11 21:27:59 +00:00
|
|
|
*mode = state.pipeline->depthTest;
|
|
|
|
*write = state.pipeline->depthWrite;
|
2017-02-17 08:48:43 +00:00
|
|
|
}
|
|
|
|
|
2018-07-05 03:11:52 +00:00
|
|
|
void lovrGraphicsSetDepthTest(CompareMode mode, bool write) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->depthTest != mode || state.pipeline->depthWrite != write) {
|
|
|
|
state.pipeline->depthTest = mode;
|
|
|
|
state.pipeline->depthWrite = write;
|
|
|
|
state.pipeline->dirty = true;
|
|
|
|
}
|
2016-11-27 02:58:58 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 08:36:29 +00:00
|
|
|
Font* lovrGraphicsGetFont() {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (!state.pipeline->font) {
|
2017-08-09 06:49:17 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->font;
|
2017-08-08 08:36:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetFont(Font* font) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->font != font) {
|
|
|
|
lovrRetain(font);
|
|
|
|
lovrRelease(state.pipeline->font);
|
|
|
|
state.pipeline->font = font;
|
|
|
|
}
|
2017-08-08 08:36:29 +00:00
|
|
|
}
|
|
|
|
|
2017-11-23 04:26:01 +00:00
|
|
|
bool lovrGraphicsIsGammaCorrect() {
|
|
|
|
return state.gammaCorrect;
|
|
|
|
}
|
|
|
|
|
2016-10-01 20:48:31 +00:00
|
|
|
float lovrGraphicsGetLineWidth() {
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->lineWidth;
|
2016-10-01 20:48:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetLineWidth(float width) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->lineWidth != width) {
|
|
|
|
state.pipeline->lineWidth = width;
|
|
|
|
}
|
2016-10-01 20:48:31 +00:00
|
|
|
}
|
|
|
|
|
2016-11-13 01:38:49 +00:00
|
|
|
float lovrGraphicsGetPointSize() {
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->pointSize;
|
2016-11-13 01:38:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetPointSize(float size) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->pointSize != size) {
|
|
|
|
state.pipeline->pointSize = size;
|
|
|
|
}
|
2016-11-13 01:38:49 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 08:32:15 +00:00
|
|
|
Shader* lovrGraphicsGetShader() {
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->shader;
|
2017-08-08 08:32:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetShader(Shader* shader) {
|
2018-08-09 01:07:48 +00:00
|
|
|
lovrAssert(!shader || lovrShaderGetType(shader) == SHADER_GRAPHICS, "Compute shaders can not be set as the active shader");
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->shader != shader) {
|
|
|
|
lovrRetain(shader);
|
|
|
|
lovrRelease(state.pipeline->shader);
|
|
|
|
state.pipeline->shader = shader;
|
|
|
|
state.pipeline->dirty = true;
|
|
|
|
}
|
2017-08-08 08:32:15 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 02:37:03 +00:00
|
|
|
void lovrGraphicsGetStencilTest(CompareMode* mode, int* value) {
|
2018-12-11 21:27:59 +00:00
|
|
|
*mode = state.pipeline->stencilMode;
|
|
|
|
*value = state.pipeline->stencilValue;
|
2017-12-19 02:37:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lovrGraphicsSetStencilTest(CompareMode mode, int value) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->stencilMode != mode || state.pipeline->stencilValue != value) {
|
|
|
|
state.pipeline->stencilMode = mode;
|
|
|
|
state.pipeline->stencilValue = value;
|
|
|
|
}
|
2017-12-19 02:37:03 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
Winding lovrGraphicsGetWinding() {
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->winding;
|
2016-10-03 19:02:49 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 07:54:33 +00:00
|
|
|
void lovrGraphicsSetWinding(Winding winding) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->winding != winding) {
|
|
|
|
state.pipeline->winding = winding;
|
|
|
|
}
|
2016-10-03 19:02:49 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 08:14:09 +00:00
|
|
|
bool lovrGraphicsIsWireframe() {
|
2018-12-11 21:27:59 +00:00
|
|
|
return state.pipeline->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
|
2018-12-11 21:27:59 +00:00
|
|
|
if (state.pipeline->wireframe != wireframe) {
|
|
|
|
state.pipeline->wireframe = wireframe;
|
|
|
|
}
|
2017-08-02 07:54:33 +00:00
|
|
|
#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() {
|
2018-07-17 06:51:11 +00:00
|
|
|
lovrAssert(++state.transform < MAX_TRANSFORMS, "Unbalanced matrix stack (more pushes than pops?)");
|
|
|
|
mat4_init(state.transforms[state.transform], state.transforms[state.transform - 1]);
|
2016-09-21 07:55:53 +00:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:05:04 +00:00
|
|
|
void lovrGraphicsPop() {
|
2018-07-17 06:51:11 +00:00
|
|
|
lovrAssert(--state.transform >= 0, "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-11-27 23:03:05 +00:00
|
|
|
void lovrGraphicsTranslate(vec3 translation) {
|
|
|
|
mat4_translate(state.transforms[state.transform], translation[0], translation[1], translation[2]);
|
2016-09-23 04:53:17 +00:00
|
|
|
}
|
|
|
|
|
2018-11-27 23:03:05 +00:00
|
|
|
void lovrGraphicsRotate(quat rotation) {
|
|
|
|
mat4_rotateQuat(state.transforms[state.transform], rotation);
|
2016-09-23 04:53:17 +00:00
|
|
|
}
|
|
|
|
|
2018-11-27 23:03:05 +00:00
|
|
|
void lovrGraphicsScale(vec3 scale) {
|
|
|
|
mat4_scale(state.transforms[state.transform], scale[0], scale[1], scale[2]);
|
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
|
|
|
}
|
|
|
|
|
2018-10-27 00:17:18 +00:00
|
|
|
void lovrGraphicsSetProjection(mat4 projection) {
|
|
|
|
mat4_set(state.camera.projection[0], projection);
|
|
|
|
mat4_set(state.camera.projection[1], projection);
|
|
|
|
}
|
|
|
|
|
2018-08-09 01:08:28 +00:00
|
|
|
// Rendering
|
2016-09-29 05:10:03 +00:00
|
|
|
|
2018-12-07 23:57:45 +00:00
|
|
|
float* lovrGraphicsGetVertexPointer(uint32_t count) {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrAssert(count <= MAX_VERTICES, "Hey now! Up to %d vertices are allowed per primitive", MAX_VERTICES);
|
|
|
|
|
|
|
|
if (state.vertexCursor + count > MAX_VERTICES) {
|
|
|
|
lovrGraphicsFlush();
|
|
|
|
state.batchVertex = state.vertexCursor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lovrMeshMapVertices(state.defaultMesh, state.vertexCursor * 8 * sizeof(float));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t* lovrGraphicsGetIndexPointer(uint32_t count) {
|
|
|
|
lovrAssert(count <= MAX_INDICES, "Whoa there! Up to %d indices are allowed per primitive", MAX_INDICES);
|
|
|
|
|
|
|
|
if (state.indexCursor + count > MAX_INDICES) {
|
|
|
|
lovrGraphicsFlush();
|
|
|
|
state.batchIndex = state.indexCursor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lovrMeshMapIndices(state.defaultMesh, count ? MAX_INDICES : 0, sizeof(uint16_t), state.indexCursor * sizeof(uint16_t));
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2018-07-16 00:05:06 +00:00
|
|
|
void lovrGraphicsClear(Color* color, float* depth, int* stencil) {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrGpuClear(state.pipeline->canvas ? state.pipeline->canvas : state.camera.canvas, color, depth, stencil);
|
2017-02-03 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2018-10-26 16:14:57 +00:00
|
|
|
void lovrGraphicsDiscard(bool color, bool depth, bool stencil) {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrGpuDiscard(state.pipeline->canvas ? state.pipeline->canvas : state.camera.canvas, color, depth, stencil);
|
2018-10-26 16:14:57 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
void lovrGraphicsFlush() {
|
|
|
|
if (state.batchSize == 0) {
|
|
|
|
return;
|
2018-08-31 13:03:35 +00:00
|
|
|
}
|
2018-07-16 00:05:06 +00:00
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
// Resolve objects
|
2018-12-25 02:44:38 +00:00
|
|
|
DrawRequest* draw = &state.batch;
|
2018-12-11 05:30:55 +00:00
|
|
|
Mesh* mesh = draw->mesh ? draw->mesh : state.defaultMesh;
|
2018-12-11 21:27:59 +00:00
|
|
|
Canvas* canvas = state.pipeline->canvas ? state.pipeline->canvas : state.camera.canvas;
|
2018-12-11 05:30:55 +00:00
|
|
|
Material* material = draw->material ? draw->material : (state.defaultMaterial ? state.defaultMaterial : (state.defaultMaterial = lovrMaterialCreate()));
|
2018-12-11 21:27:59 +00:00
|
|
|
Shader* shader = state.pipeline->shader ? state.pipeline->shader : (state.defaultShaders[draw->shader] ? state.defaultShaders[draw->shader] : (state.defaultShaders[draw->shader] = lovrShaderCreateDefault(draw->shader)));
|
2018-08-31 13:03:35 +00:00
|
|
|
|
|
|
|
if (!draw->material) {
|
2018-12-11 05:30:55 +00:00
|
|
|
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, draw->diffuseTexture);
|
|
|
|
lovrMaterialSetTexture(material, TEXTURE_ENVIRONMENT_MAP, draw->environmentMap);
|
2018-07-16 00:05:06 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
// Camera
|
2018-08-31 13:03:35 +00:00
|
|
|
lovrShaderSetMatrices(shader, "lovrViews", state.camera.viewMatrix[0], 0, 32);
|
|
|
|
lovrShaderSetMatrices(shader, "lovrProjections", state.camera.projection[0], 0, 32);
|
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
// Pose
|
2018-12-05 18:22:12 +00:00
|
|
|
if (draw->pose) {
|
|
|
|
lovrShaderSetMatrices(shader, "lovrPose", draw->pose, 0, MAX_BONES * 16);
|
2017-01-13 09:59:00 +00:00
|
|
|
} else {
|
2018-10-07 04:58:40 +00:00
|
|
|
lovrShaderSetMatrices(shader, "lovrPose", (float[16]) MAT4_IDENTITY, 0, 16);
|
2018-08-31 13:03:35 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
// Viewport
|
|
|
|
bool stereo = !draw->mono && (canvas ? lovrCanvasIsStereo(canvas) : state.camera.stereo);
|
|
|
|
float w = (canvas ? lovrCanvasGetWidth(canvas) : state.width) >> stereo;
|
|
|
|
float h = canvas ? lovrCanvasGetHeight(canvas) : state.height;
|
|
|
|
float viewports[2][4] = { { 0, 0, w, h, }, { w, 0, w, h } };
|
|
|
|
int viewportCount = 1 + stereo;
|
2018-08-31 13:03:35 +00:00
|
|
|
lovrShaderSetInts(shader, "lovrViewportCount", &viewportCount, 0, 1);
|
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
// Point size
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrShaderSetFloats(shader, "lovrPointSize", &state.pipeline->pointSize, 0, 1);
|
|
|
|
|
|
|
|
// Buffers and Mesh
|
|
|
|
int vertexCount = state.vertexCursor - state.batchVertex;
|
|
|
|
int indexCount = state.indexCursor - state.batchIndex;
|
|
|
|
lovrBufferFlush(lovrShaderBlockGetBuffer(state.block), 0, MAX_BATCH_SIZE * (16 * sizeof(float) + 4 * sizeof(float)));
|
|
|
|
lovrBufferFlush(state.vertexMap, state.batchVertex, vertexCount);
|
|
|
|
|
|
|
|
if (!draw->mesh) {
|
|
|
|
if (indexCount > 0) {
|
|
|
|
lovrMeshSetDrawRange(state.defaultMesh, state.batchIndex, indexCount);
|
|
|
|
} else {
|
|
|
|
lovrMeshSetDrawRange(state.defaultMesh, state.batchVertex, vertexCount);
|
|
|
|
}
|
2017-11-21 05:16:16 +00:00
|
|
|
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrMeshSetDrawMode(state.defaultMesh, draw->mode);
|
|
|
|
lovrMeshFlushVertices(state.defaultMesh, state.batchVertex * 8 * sizeof(float), vertexCount * 8 * sizeof(float));
|
|
|
|
lovrMeshFlushIndices(state.defaultMesh);
|
|
|
|
}
|
2018-08-31 13:03:35 +00:00
|
|
|
|
|
|
|
// Bind
|
|
|
|
lovrCanvasBind(canvas, true);
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrGpuBindPipeline(state.pipeline);
|
2018-12-11 05:30:55 +00:00
|
|
|
lovrMaterialBind(material, shader);
|
2018-08-31 13:03:35 +00:00
|
|
|
lovrMeshBind(mesh, shader, viewportCount);
|
2018-12-11 05:30:55 +00:00
|
|
|
lovrShaderSetBlock(shader, "lovrDrawData", state.block, ACCESS_READ);
|
2018-08-31 13:03:35 +00:00
|
|
|
|
|
|
|
// Draw
|
|
|
|
if (lovrGpuGetSupported()->singlepass) {
|
2018-12-11 05:30:55 +00:00
|
|
|
int instances = draw->instances * viewportCount;
|
2018-08-31 13:03:35 +00:00
|
|
|
lovrGpuSetViewports(&viewports[0][0], viewportCount);
|
|
|
|
lovrShaderBind(shader);
|
|
|
|
lovrMeshDraw(mesh, instances);
|
2017-01-13 09:59:00 +00:00
|
|
|
} else {
|
2018-08-31 13:03:35 +00:00
|
|
|
for (int i = 0; i < viewportCount; i++) {
|
|
|
|
lovrGpuSetViewports(&viewports[i][0], 1);
|
|
|
|
lovrShaderSetInts(shader, "lovrViewportIndex", &i, 0, 1);
|
|
|
|
lovrShaderBind(shader);
|
|
|
|
lovrMeshDraw(mesh, draw->instances);
|
|
|
|
}
|
2017-01-13 09:59:00 +00:00
|
|
|
}
|
2016-09-30 02:39:25 +00:00
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
state.batchSize = 0;
|
2018-12-11 21:27:59 +00:00
|
|
|
state.batchVertex = state.vertexCursor;
|
|
|
|
state.batchIndex = state.indexCursor;
|
2018-12-11 05:30:55 +00:00
|
|
|
}
|
|
|
|
|
2018-12-25 02:44:38 +00:00
|
|
|
void lovrGraphicsDraw(DrawRequest* draw) {
|
2018-12-12 06:10:29 +00:00
|
|
|
if (state.batchSize > 0 && !batchable(draw)) {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrGraphicsFlush();
|
|
|
|
}
|
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
if (state.batchSize == 0) {
|
2018-12-25 02:44:38 +00:00
|
|
|
memcpy(&state.batch, draw, sizeof(DrawRequest));
|
2018-12-12 06:23:38 +00:00
|
|
|
} else if (draw->mesh && draw->instances <= 1) {
|
|
|
|
state.batch.instances++;
|
2018-08-31 13:03:35 +00:00
|
|
|
}
|
2018-12-11 05:30:55 +00:00
|
|
|
|
|
|
|
// Geometry
|
|
|
|
if (!draw->mesh) {
|
2018-12-11 21:27:59 +00:00
|
|
|
if (draw->vertex.data) {
|
|
|
|
void* vertices = lovrGraphicsGetVertexPointer(draw->vertex.count);
|
|
|
|
memcpy(vertices, draw->vertex.data, draw->vertex.count * 8 * sizeof(float));
|
|
|
|
}
|
2018-12-11 05:30:55 +00:00
|
|
|
|
|
|
|
if (draw->index.count) {
|
2018-12-11 21:27:59 +00:00
|
|
|
// TODO conditionally use BaseVertex when it is supported to avoid this
|
2018-12-14 07:05:56 +00:00
|
|
|
if (draw->index.data) {
|
|
|
|
for (uint32_t i = 0; i < draw->index.count; i++) {
|
|
|
|
draw->index.data[i] += state.vertexCursor;
|
|
|
|
}
|
2018-12-11 21:27:59 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 05:30:55 +00:00
|
|
|
if (draw->index.data) {
|
2018-12-11 21:27:59 +00:00
|
|
|
uint16_t* indices = lovrGraphicsGetIndexPointer(draw->index.count);
|
2018-12-11 05:30:55 +00:00
|
|
|
memcpy(indices, draw->index.data, draw->index.count * sizeof(uint16_t));
|
|
|
|
}
|
2018-12-11 21:27:59 +00:00
|
|
|
|
|
|
|
state.indexCursor += draw->index.count;
|
2018-12-11 05:30:55 +00:00
|
|
|
} else {
|
2018-12-11 21:27:59 +00:00
|
|
|
lovrMeshMapIndices(state.defaultMesh, 0, 0, 0);
|
2018-12-11 05:30:55 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 21:27:59 +00:00
|
|
|
void* vertexMap = lovrBufferMap(state.vertexMap, state.vertexCursor * sizeof(uint8_t));
|
|
|
|
memset(vertexMap, state.batchSize, draw->vertex.count * sizeof(uint8_t));
|
|
|
|
state.vertexCursor += draw->vertex.count;
|
2018-12-11 05:30:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Transform and color
|
2018-12-11 21:27:59 +00:00
|
|
|
struct { float model[MAX_BATCH_SIZE][16]; float color[MAX_BATCH_SIZE][4]; } *drawData;
|
2018-12-11 05:30:55 +00:00
|
|
|
drawData = lovrBufferMap(lovrShaderBlockGetBuffer(state.block), 0);
|
|
|
|
|
|
|
|
memcpy(drawData->model[state.batchSize], state.transforms[state.transform], 16 * sizeof(float));
|
|
|
|
if (draw->transform) { mat4_multiply(drawData->model[state.batchSize], draw->transform); }
|
|
|
|
|
2018-12-11 21:27:59 +00:00
|
|
|
memcpy(drawData->color[state.batchSize], (float*) &state.pipeline->color, 4 * sizeof(float));
|
2018-12-11 05:30:55 +00:00
|
|
|
|
2018-12-11 21:27:59 +00:00
|
|
|
if (++state.batchSize >= MAX_BATCH_SIZE) {
|
|
|
|
lovrGraphicsFlush();
|
|
|
|
}
|
2016-11-08 07:16:33 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
void lovrGraphicsPoints(uint32_t count) {
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_POINTS,
|
2018-12-07 23:57:45 +00:00
|
|
|
.vertex.count = count
|
2018-07-14 00:12:30 +00:00
|
|
|
});
|
2016-09-29 07:00:02 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
void lovrGraphicsLine(uint32_t count) {
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_LINE_STRIP,
|
2018-12-07 23:57:45 +00:00
|
|
|
.vertex.count = count
|
2018-07-14 00:12:30 +00:00
|
|
|
});
|
2016-09-29 07:00:02 +00:00
|
|
|
}
|
2017-03-12 23:57:27 +00:00
|
|
|
|
2018-12-13 02:43:04 +00:00
|
|
|
void lovrGraphicsTriangle(DrawStyle style, Material* material, float points[9]) {
|
|
|
|
if (style == STYLE_LINE) {
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-15 06:50:06 +00:00
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_LINE_LOOP,
|
2018-07-14 00:12:30 +00:00
|
|
|
.vertex.count = 3,
|
|
|
|
.vertex.data = (float[]) {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
});
|
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]);
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-15 06:50:06 +00:00
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_TRIANGLES,
|
2018-07-14 00:12:30 +00:00
|
|
|
.vertex.count = 3,
|
|
|
|
.vertex.data = (float[]) {
|
|
|
|
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-12-13 02:43:04 +00:00
|
|
|
void lovrGraphicsPlane(DrawStyle style, Material* material, mat4 transform) {
|
|
|
|
if (style == STYLE_LINE) {
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.transform = transform,
|
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_LINE_LOOP,
|
2018-07-14 00:12:30 +00:00
|
|
|
.vertex.count = 4,
|
|
|
|
.vertex.data = (float[]) {
|
|
|
|
-.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
|
|
|
|
}
|
|
|
|
});
|
2018-12-13 02:43:04 +00:00
|
|
|
} else {
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.transform = transform,
|
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_TRIANGLES,
|
2018-07-14 00:12:30 +00:00
|
|
|
.vertex.count = 4,
|
|
|
|
.vertex.data = (float[]) {
|
|
|
|
-.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
|
2018-12-11 21:27:59 +00:00
|
|
|
},
|
|
|
|
.index.count = 6,
|
|
|
|
.index.data = (uint16_t[]) { 0, 1, 2, 2, 1, 3 }
|
2018-07-14 00:12:30 +00:00
|
|
|
});
|
2016-10-04 03:56:45 +00:00
|
|
|
}
|
2017-01-13 09:59:00 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 02:43:04 +00:00
|
|
|
void lovrGraphicsBox(DrawStyle style, Material* material, mat4 transform) {
|
|
|
|
if (style == STYLE_LINE) {
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.transform = transform,
|
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_LINES,
|
2018-07-14 00:12:30 +00:00
|
|
|
.vertex.count = 8,
|
|
|
|
.vertex.data = (float[]) {
|
|
|
|
// Front
|
|
|
|
-.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,
|
|
|
|
// Back
|
|
|
|
-.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
|
|
|
|
},
|
|
|
|
.index.count = 24,
|
|
|
|
.index.data = (uint16_t[]) {
|
|
|
|
0, 1, 1, 2, 2, 3, 3, 0, // Front
|
|
|
|
4, 5, 5, 6, 6, 7, 7, 4, // Back
|
|
|
|
0, 4, 1, 5, 2, 6, 3, 7 // Connections
|
|
|
|
}
|
|
|
|
});
|
2016-10-01 19:10:38 +00:00
|
|
|
} else {
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.transform = transform,
|
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_TRIANGLES,
|
2018-12-11 21:27:59 +00:00
|
|
|
.vertex.count = 24,
|
2018-07-14 00:12:30 +00:00
|
|
|
.vertex.data = (float[]) {
|
|
|
|
// Front
|
|
|
|
-.5, -.5, -.5, 0, 0, -1, 0, 0,
|
|
|
|
-.5, .5, -.5, 0, 0, -1, 0, 1,
|
|
|
|
.5, -.5, -.5, 0, 0, -1, 1, 0,
|
|
|
|
.5, .5, -.5, 0, 0, -1, 1, 1,
|
|
|
|
// Right
|
|
|
|
.5, .5, -.5, 1, 0, 0, 0, 1,
|
|
|
|
.5, .5, .5, 1, 0, 0, 1, 1,
|
|
|
|
.5, -.5, -.5, 1, 0, 0, 0, 0,
|
|
|
|
.5, -.5, .5, 1, 0, 0, 1, 0,
|
|
|
|
// Back
|
|
|
|
.5, -.5, .5, 0, 0, 1, 0, 0,
|
|
|
|
.5, .5, .5, 0, 0, 1, 0, 1,
|
|
|
|
-.5, -.5, .5, 0, 0, 1, 1, 0,
|
|
|
|
-.5, .5, .5, 0, 0, 1, 1, 1,
|
|
|
|
// Left
|
|
|
|
-.5, .5, .5, -1, 0, 0, 0, 1,
|
|
|
|
-.5, .5, -.5, -1, 0, 0, 1, 1,
|
|
|
|
-.5, -.5, .5, -1, 0, 0, 0, 0,
|
|
|
|
-.5, -.5, -.5, -1, 0, 0, 1, 0,
|
|
|
|
// Bottom
|
|
|
|
-.5, -.5, -.5, 0, -1, 0, 0, 0,
|
|
|
|
.5, -.5, -.5, 0, -1, 0, 1, 0,
|
|
|
|
-.5, -.5, .5, 0, -1, 0, 0, 1,
|
|
|
|
.5, -.5, .5, 0, -1, 0, 1, 1,
|
|
|
|
// Top
|
|
|
|
-.5, .5, -.5, 0, 1, 0, 0, 1,
|
|
|
|
-.5, .5, .5, 0, 1, 0, 0, 0,
|
|
|
|
.5, .5, -.5, 0, 1, 0, 1, 1,
|
|
|
|
.5, .5, .5, 0, 1, 0, 1, 0
|
2018-12-11 21:27:59 +00:00
|
|
|
},
|
|
|
|
.index.count = 36,
|
|
|
|
.index.data = (uint16_t[]) {
|
|
|
|
0, 1, 2, 2, 1, 3,
|
|
|
|
4, 5, 6, 6, 5, 7,
|
|
|
|
8, 9, 10, 10, 9, 11,
|
|
|
|
12, 13, 14, 14, 13, 15,
|
|
|
|
16, 17, 18, 18, 17, 19,
|
|
|
|
20, 21, 22, 22, 21, 23
|
2018-07-14 00:12:30 +00:00
|
|
|
}
|
|
|
|
});
|
2016-10-01 19:10:38 +00:00
|
|
|
}
|
2016-09-30 06:18:51 +00:00
|
|
|
}
|
2016-10-24 22:02:23 +00:00
|
|
|
|
2018-12-13 02:43:04 +00:00
|
|
|
void lovrGraphicsArc(DrawStyle style, 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;
|
2018-12-07 23:57:45 +00:00
|
|
|
float* vertices = lovrGraphicsGetVertexPointer(count);
|
2017-11-22 19:32:30 +00:00
|
|
|
|
2018-03-22 05:03:03 +00:00
|
|
|
if (hasCenterPoint) {
|
2018-12-07 23:57:45 +00:00
|
|
|
memcpy(vertices, ((float[]) { 0, 0, 0, 0, 0, 1, .5, .5 }), 8 * sizeof(float));
|
|
|
|
vertices += 8;
|
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;
|
2018-12-07 23:57:45 +00:00
|
|
|
memcpy(vertices, ((float[]) { x, y, 0, 0, 0, 1, x + .5, 1 - (y + .5) }), 8 * sizeof(float));
|
|
|
|
vertices += 8;
|
2018-03-22 05:03:03 +00:00
|
|
|
theta += angleShift;
|
2017-11-22 04:53:34 +00:00
|
|
|
}
|
|
|
|
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.transform = transform,
|
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = style == STYLE_LINE ? (arcMode == ARC_MODE_OPEN ? DRAW_LINE_STRIP : DRAW_LINE_LOOP) : DRAW_TRIANGLE_FAN,
|
2018-12-07 23:57:45 +00:00
|
|
|
.vertex.count = count
|
2018-07-14 00:12:30 +00:00
|
|
|
});
|
2017-11-22 04:53:34 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 02:43:04 +00:00
|
|
|
void lovrGraphicsCircle(DrawStyle style, Material* material, mat4 transform, int segments) {
|
|
|
|
lovrGraphicsArc(style, 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-12-07 23:57:45 +00:00
|
|
|
float* vertices = lovrGraphicsGetVertexPointer(vertexCount);
|
2018-12-11 21:27:59 +00:00
|
|
|
uint16_t* indices = lovrGraphicsGetIndexPointer(indexCount);
|
2018-12-07 23:57:45 +00:00
|
|
|
float* baseVertex = vertices;
|
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-12-07 23:57:45 +00:00
|
|
|
*vertices++ = x; \
|
|
|
|
*vertices++ = y; \
|
|
|
|
*vertices++ = z; \
|
|
|
|
*vertices++ = nx; \
|
|
|
|
*vertices++ = ny; \
|
|
|
|
*vertices++ = nz; \
|
|
|
|
*vertices++ = 0; \
|
|
|
|
*vertices++ = 0;
|
2017-06-21 03:54:22 +00:00
|
|
|
#define PUSH_CYLINDER_TRIANGLE(i1, i2, i3) \
|
2018-12-07 23:57:45 +00:00
|
|
|
*indices++ = i1; \
|
|
|
|
*indices++ = i2; \
|
|
|
|
*indices++ = 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-12-14 07:05:56 +00:00
|
|
|
int topOffset = (segments + 1) * 2 + state.vertexCursor;
|
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-12-14 07:05:56 +00:00
|
|
|
int bottomOffset = (segments + 1) * 2 + (1 + segments + 1) * (capped && r1 != 0) + state.vertexCursor;
|
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-12-14 07:05:56 +00:00
|
|
|
int j = 2 * i + state.vertexCursor;
|
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
|
|
|
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_TRIANGLES,
|
2018-12-07 23:57:45 +00:00
|
|
|
.vertex.count = vertexCount,
|
|
|
|
.index.count = indexCount
|
2018-07-14 00:12:30 +00:00
|
|
|
});
|
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-12-07 23:57:45 +00:00
|
|
|
uint32_t vertexCount = (segments + 1) * (segments + 1);
|
|
|
|
uint32_t indexCount = segments * segments * 6;
|
|
|
|
float* vertices = lovrGraphicsGetVertexPointer(vertexCount);
|
2018-12-11 21:27:59 +00:00
|
|
|
uint16_t* indices = lovrGraphicsGetIndexPointer(indexCount);
|
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);
|
2018-12-07 23:57:45 +00:00
|
|
|
memcpy(vertices, ((float[]) { x, y, z, x, y, z, u, 1 - v }), 8 * sizeof(float));
|
|
|
|
vertices += 8;
|
2017-06-22 06:10:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < segments; i++) {
|
2018-12-07 23:57:45 +00:00
|
|
|
uint16_t offset0 = i * (segments + 1);
|
|
|
|
uint16_t offset1 = (i + 1) * (segments + 1);
|
2017-06-22 06:10:45 +00:00
|
|
|
for (int j = 0; j < segments; j++) {
|
2018-12-14 07:05:56 +00:00
|
|
|
uint16_t i0 = offset0 + j + state.vertexCursor;
|
|
|
|
uint16_t i1 = offset1 + j + state.vertexCursor;
|
2018-12-07 23:57:45 +00:00
|
|
|
memcpy(indices, ((uint16_t[]) { i0, i1, i0 + 1, i1, i1 + 1, i0 + 1 }), 6 * sizeof(uint16_t));
|
|
|
|
indices += 6;
|
2017-06-22 06:10:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.transform = transform,
|
|
|
|
.material = material,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_TRIANGLES,
|
2018-12-07 23:57:45 +00:00
|
|
|
.vertex.count = vertexCount,
|
|
|
|
.index.count = indexCount
|
2018-07-14 00:12:30 +00:00
|
|
|
});
|
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-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");
|
2018-07-15 01:26:02 +00:00
|
|
|
lovrGraphicsPushPipeline();
|
2018-02-26 10:10:53 +00:00
|
|
|
lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE);
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.shader = type == TEXTURE_CUBE ? SHADER_CUBE : SHADER_PANO,
|
2018-12-11 05:30:55 +00:00
|
|
|
.diffuseTexture = type == TEXTURE_2D ? texture : NULL,
|
|
|
|
.environmentMap = type == TEXTURE_CUBE ? texture : NULL,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_TRIANGLE_STRIP,
|
2018-07-14 00:12:30 +00:00
|
|
|
.vertex.count = 4,
|
|
|
|
.vertex.data = (float[]) {
|
|
|
|
-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-07-15 01:26:02 +00:00
|
|
|
lovrGraphicsPopPipeline();
|
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;
|
2018-12-07 23:57:45 +00:00
|
|
|
float* vertices = lovrGraphicsGetVertexPointer(maxVertices);
|
|
|
|
lovrFontRender(font, str, wrap, halign, valign, vertices, &offsety, &vertexCount);
|
2017-08-02 02:58:24 +00:00
|
|
|
|
|
|
|
lovrGraphicsPush();
|
2018-03-05 07:06:34 +00:00
|
|
|
lovrGraphicsMatrixTransform(transform);
|
2018-11-27 23:03:05 +00:00
|
|
|
lovrGraphicsScale((float[3]) { scale, scale, scale });
|
|
|
|
lovrGraphicsTranslate((float[3]) { 0, offsety, 0 });
|
2018-12-12 06:52:33 +00:00
|
|
|
lovrGraphicsPushPipeline();
|
|
|
|
lovrGraphicsSetAlphaSampling(true);
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-07-14 00:12:30 +00:00
|
|
|
.shader = SHADER_FONT,
|
2018-12-11 05:30:55 +00:00
|
|
|
.diffuseTexture = font->texture,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_TRIANGLES,
|
2018-12-07 23:57:45 +00:00
|
|
|
.vertex.count = vertexCount
|
2018-07-14 00:12:30 +00:00
|
|
|
});
|
2018-12-12 06:52:33 +00:00
|
|
|
lovrGraphicsPopPipeline();
|
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
|
|
|
|
2018-10-01 01:40:51 +00:00
|
|
|
void lovrGraphicsFill(Texture* texture, float u, float v, float w, float h) {
|
2018-07-15 01:26:02 +00:00
|
|
|
lovrGraphicsPushPipeline();
|
2018-03-19 19:47:35 +00:00
|
|
|
lovrGraphicsSetDepthTest(COMPARE_NONE, false);
|
2018-12-25 02:44:38 +00:00
|
|
|
lovrGraphicsDraw(&(DrawRequest) {
|
2018-12-11 05:30:55 +00:00
|
|
|
.mono = true,
|
2018-07-14 00:12:30 +00:00
|
|
|
.shader = SHADER_FILL,
|
2018-12-11 05:30:55 +00:00
|
|
|
.diffuseTexture = texture,
|
2018-12-13 02:43:04 +00:00
|
|
|
.mode = DRAW_TRIANGLE_STRIP,
|
2018-07-14 00:12:30 +00:00
|
|
|
.vertex.count = 4,
|
|
|
|
.vertex.data = (float[]) {
|
2018-10-01 01:40:51 +00:00
|
|
|
-1, 1, 0, 0, 0, 0, u, v + h,
|
|
|
|
-1, -1, 0, 0, 0, 0, u, v,
|
|
|
|
1, 1, 0, 0, 0, 0, u + w, v + h,
|
|
|
|
1, -1, 0, 0, 0, 0, u + w, v
|
2017-10-21 20:06:23 +00:00
|
|
|
}
|
2018-07-14 00:12:30 +00:00
|
|
|
});
|
2018-07-15 01:26:02 +00:00
|
|
|
lovrGraphicsPopPipeline();
|
2017-12-10 04:07:32 +00:00
|
|
|
}
|