mirror of https://github.com/bjornbytes/lovr.git
Put non-opengl-specific stuff in their own files;
This commit is contained in:
parent
fbcee9ac9c
commit
c87645e8ef
|
@ -423,11 +423,15 @@ if(LOVR_ENABLE_GRAPHICS)
|
|||
add_definitions(-DLOVR_ENABLE_GRAPHICS)
|
||||
target_sources(lovr PRIVATE
|
||||
src/graphics/animator.c
|
||||
src/graphics/canvas.c
|
||||
src/graphics/font.c
|
||||
src/graphics/graphics.c
|
||||
src/graphics/material.c
|
||||
src/graphics/mesh.c
|
||||
src/graphics/model.c
|
||||
src/graphics/opengl.c
|
||||
src/graphics/shader.c
|
||||
src/graphics/texture.c
|
||||
src/api/graphics.c
|
||||
src/api/types/animator.c
|
||||
src/api/types/canvas.c
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#include "graphics/buffer.h"
|
||||
|
||||
size_t lovrBufferGetSize(Buffer* buffer) {
|
||||
return buffer->size;
|
||||
}
|
||||
|
||||
BufferUsage lovrBufferGetUsage(Buffer* buffer) {
|
||||
return buffer->usage;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#include "graphics/opengl.h"
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#include "graphics/canvas.h"
|
||||
|
||||
const Attachment* lovrCanvasGetAttachments(Canvas* canvas, int* count) {
|
||||
if (count) *count = canvas->attachmentCount;
|
||||
return canvas->attachments;
|
||||
}
|
||||
|
||||
void lovrCanvasSetAttachments(Canvas* canvas, Attachment* attachments, int count) {
|
||||
lovrAssert(count > 0, "A Canvas must have at least one attached Texture");
|
||||
lovrAssert(count <= MAX_CANVAS_ATTACHMENTS, "Only %d textures can be attached to a Canvas, got %d\n", MAX_CANVAS_ATTACHMENTS, count);
|
||||
|
||||
if (!canvas->needsAttach && count == canvas->attachmentCount && !memcmp(canvas->attachments, attachments, count * sizeof(Attachment))) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Texture* texture = attachments[i].texture;
|
||||
int width = lovrTextureGetWidth(texture, attachments[i].level);
|
||||
int height = lovrTextureGetHeight(texture, attachments[i].level);
|
||||
bool hasDepth = canvas->flags.depth.enabled;
|
||||
lovrAssert(!hasDepth || width == canvas->width, "Texture width of %d does not match Canvas width (%d)", width, canvas->width);
|
||||
lovrAssert(!hasDepth || height == canvas->height, "Texture height of %d does not match Canvas height (%d)", height, canvas->height);
|
||||
lovrAssert(texture->msaa == canvas->flags.msaa, "Texture MSAA does not match Canvas MSAA");
|
||||
lovrRetain(texture);
|
||||
}
|
||||
|
||||
for (int i = 0; i < canvas->attachmentCount; i++) {
|
||||
lovrRelease(canvas->attachments[i].texture);
|
||||
}
|
||||
|
||||
memcpy(canvas->attachments, attachments, count * sizeof(Attachment));
|
||||
canvas->attachmentCount = count;
|
||||
canvas->needsAttach = true;
|
||||
}
|
||||
|
||||
bool lovrCanvasIsDirty(Canvas* canvas) {
|
||||
return canvas->needsAttach;
|
||||
}
|
||||
|
||||
bool lovrCanvasIsStereo(Canvas* canvas) {
|
||||
return canvas->flags.stereo;
|
||||
}
|
||||
|
||||
int lovrCanvasGetWidth(Canvas* canvas) {
|
||||
return canvas->width;
|
||||
}
|
||||
|
||||
int lovrCanvasGetHeight(Canvas* canvas) {
|
||||
return canvas->height;
|
||||
}
|
||||
|
||||
int lovrCanvasGetMSAA(Canvas* canvas) {
|
||||
return canvas->flags.msaa;
|
||||
}
|
||||
|
||||
Texture* lovrCanvasGetDepthTexture(Canvas* canvas) {
|
||||
return canvas->depth.texture;
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
#include "data/rasterizer.h"
|
||||
#include "event/event.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "math/math.h"
|
||||
#include "util.h"
|
||||
#include "lib/math.h"
|
||||
#include "lib/stb/stb_image.h"
|
||||
|
@ -12,6 +13,14 @@
|
|||
|
||||
static GraphicsState state;
|
||||
|
||||
static void gammaCorrectColor(Color* color) {
|
||||
if (state.gammaCorrect) {
|
||||
color->r = lovrMathGammaToLinear(color->r);
|
||||
color->g = lovrMathGammaToLinear(color->g);
|
||||
color->b = lovrMathGammaToLinear(color->b);
|
||||
}
|
||||
}
|
||||
|
||||
static void onCloseWindow() {
|
||||
lovrEventPush((Event) { .type = EVENT_QUIT, .data.quit = { false, 0 } });
|
||||
}
|
||||
|
@ -410,6 +419,7 @@ uint16_t* lovrGraphicsGetIndexPointer(uint32_t count) {
|
|||
}
|
||||
|
||||
void lovrGraphicsClear(Color* color, float* depth, int* stencil) {
|
||||
if (color) gammaCorrectColor(color);
|
||||
lovrGpuClear(state.canvas ? state.canvas : state.camera.canvas, color, depth, stencil);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "graphics/mesh.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "math/math.h"
|
||||
#include "lib/math.h"
|
||||
#include "util.h"
|
||||
#include "platform.h"
|
||||
#include <stdbool.h>
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
#include "graphics/mesh.h"
|
||||
|
||||
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute) {
|
||||
lovrAssert(!map_get(&mesh->attributes, name), "Mesh already has an attribute named '%s'", name);
|
||||
lovrAssert(attribute->divisor >= 0, "Divisor can't be negative");
|
||||
map_set(&mesh->attributes, name, *attribute);
|
||||
lovrRetain(attribute->buffer);
|
||||
mesh->dirty = true;
|
||||
}
|
||||
|
||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "No attached attribute '%s' was found", name);
|
||||
lovrAssert(attribute->buffer != mesh->vbo, "Attribute '%s' was not attached from another Mesh", name);
|
||||
lovrRelease(attribute->buffer);
|
||||
map_remove(&mesh->attributes, name);
|
||||
mesh->dirty = true;
|
||||
}
|
||||
|
||||
MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name) {
|
||||
return map_get(&mesh->attributes, name);
|
||||
}
|
||||
|
||||
bool lovrMeshIsDirty(Mesh* mesh) {
|
||||
return mesh->dirty;
|
||||
}
|
||||
|
||||
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh) {
|
||||
return &mesh->format;
|
||||
}
|
||||
|
||||
bool lovrMeshIsReadable(Mesh* mesh) {
|
||||
return mesh->readable;
|
||||
}
|
||||
|
||||
DrawMode lovrMeshGetDrawMode(Mesh* mesh) {
|
||||
return mesh->mode;
|
||||
}
|
||||
|
||||
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode) {
|
||||
if (mesh->mode != mode) {
|
||||
mesh->mode = mode;
|
||||
mesh->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
int lovrMeshGetVertexCount(Mesh* mesh) {
|
||||
return mesh->count;
|
||||
}
|
||||
|
||||
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
||||
return attribute->enabled;
|
||||
}
|
||||
|
||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enable) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
||||
mesh->dirty = attribute->enabled != enable;
|
||||
attribute->enabled = enable;
|
||||
}
|
||||
|
||||
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count) {
|
||||
*start = mesh->rangeStart;
|
||||
*count = mesh->rangeCount;
|
||||
}
|
||||
|
||||
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count) {
|
||||
uint32_t limit = mesh->indexCount > 0 ? mesh->indexCount : mesh->count;
|
||||
lovrAssert(start + count <= limit, "Invalid mesh draw range [%d, %d]", start + 1, start + count + 1);
|
||||
if (mesh->rangeStart != start || mesh->rangeCount != count) {
|
||||
mesh->rangeStart = start;
|
||||
mesh->rangeCount = count;
|
||||
mesh->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
Material* lovrMeshGetMaterial(Mesh* mesh) {
|
||||
return mesh->material;
|
||||
}
|
||||
|
||||
void lovrMeshSetMaterial(Mesh* mesh, Material* material) {
|
||||
if (mesh->material != material) {
|
||||
lovrRetain(material);
|
||||
lovrRelease(mesh->material);
|
||||
mesh->material = material;
|
||||
mesh->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void* lovrMeshMapVertices(Mesh* mesh, size_t offset) {
|
||||
return lovrBufferMap(mesh->vbo, offset);
|
||||
}
|
||||
|
||||
void lovrMeshFlushVertices(Mesh* mesh, size_t offset, size_t size) {
|
||||
lovrBufferFlush(mesh->vbo, offset, size);
|
||||
}
|
||||
|
||||
void* lovrMeshMapIndices(Mesh* mesh, uint32_t count, size_t indexSize, size_t offset) {
|
||||
mesh->indexSize = indexSize;
|
||||
mesh->indexCount = count;
|
||||
mesh->dirty = true;
|
||||
|
||||
if (count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mesh->indexCapacity < indexSize * count) {
|
||||
mesh->indexCapacity = nextPo2(indexSize * count);
|
||||
lovrRelease(mesh->ibo);
|
||||
mesh->ibo = lovrBufferCreate(mesh->indexCapacity, NULL, mesh->usage, mesh->readable);
|
||||
}
|
||||
|
||||
return lovrBufferMap(mesh->ibo, offset);
|
||||
}
|
||||
|
||||
void lovrMeshFlushIndices(Mesh* mesh) {
|
||||
if (mesh->indexCount > 0) {
|
||||
lovrBufferFlush(mesh->ibo, 0, mesh->indexCount * mesh->indexSize);
|
||||
}
|
||||
}
|
||||
|
||||
void* lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* indexSize) {
|
||||
return *count = mesh->indexCount, *indexSize = mesh->indexSize, lovrBufferMap(mesh->ibo, 0);
|
||||
}
|
|
@ -74,14 +74,6 @@ static struct {
|
|||
|
||||
// Helper functions
|
||||
|
||||
static void gammaCorrectColor(Color* color) {
|
||||
if (state.srgb) {
|
||||
color->r = lovrMathGammaToLinear(color->r);
|
||||
color->g = lovrMathGammaToLinear(color->g);
|
||||
color->b = lovrMathGammaToLinear(color->b);
|
||||
}
|
||||
}
|
||||
|
||||
static GLenum convertCompareMode(CompareMode mode) {
|
||||
switch (mode) {
|
||||
case COMPARE_NONE: return GL_ALWAYS;
|
||||
|
@ -285,58 +277,6 @@ static TextureType getUniformTextureType(GLenum type) {
|
|||
}
|
||||
}
|
||||
|
||||
static size_t getUniformTypeLength(const Uniform* uniform) {
|
||||
size_t size = 0;
|
||||
|
||||
if (uniform->count > 1) {
|
||||
size += 2 + floor(log10(uniform->count)) + 1; // "[count]"
|
||||
}
|
||||
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_MATRIX: size += 4; break;
|
||||
case UNIFORM_FLOAT: size += uniform->components == 1 ? 5 : 4; break;
|
||||
case UNIFORM_INT: size += uniform->components == 1 ? 3 : 5; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static const char* getUniformTypeName(const Uniform* uniform) {
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_FLOAT:
|
||||
switch (uniform->components) {
|
||||
case 1: return "float";
|
||||
case 2: return "vec2";
|
||||
case 3: return "vec3";
|
||||
case 4: return "vec4";
|
||||
}
|
||||
break;
|
||||
|
||||
case UNIFORM_INT:
|
||||
switch (uniform->components) {
|
||||
case 1: return "int";
|
||||
case 2: return "ivec2";
|
||||
case 3: return "ivec3";
|
||||
case 4: return "ivec4";
|
||||
}
|
||||
break;
|
||||
|
||||
case UNIFORM_MATRIX:
|
||||
switch (uniform->components) {
|
||||
case 2: return "mat2";
|
||||
case 3: return "mat3";
|
||||
case 4: return "mat4";
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
lovrThrow("Unreachable");
|
||||
return "";
|
||||
}
|
||||
|
||||
// TODO really ought to have TextureType-specific default textures
|
||||
static Texture* lovrGpuGetDefaultTexture() {
|
||||
if (!state.defaultTexture) {
|
||||
|
@ -759,7 +699,6 @@ void lovrGpuClear(Canvas* canvas, Color* color, float* depth, int* stencil) {
|
|||
lovrCanvasBind(canvas, true);
|
||||
|
||||
if (color) {
|
||||
gammaCorrectColor(color);
|
||||
int count = canvas ? canvas->attachmentCount : 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
glClearBufferfv(GL_COLOR, i, (float[]) { color->r, color->g, color->b, color->a });
|
||||
|
@ -1081,34 +1020,6 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int x,
|
|||
}
|
||||
}
|
||||
|
||||
int lovrTextureGetWidth(Texture* texture, int mipmap) {
|
||||
return MAX(texture->width >> mipmap, 1);
|
||||
}
|
||||
|
||||
int lovrTextureGetHeight(Texture* texture, int mipmap) {
|
||||
return MAX(texture->height >> mipmap, 1);
|
||||
}
|
||||
|
||||
int lovrTextureGetDepth(Texture* texture, int mipmap) {
|
||||
return texture->type == TEXTURE_VOLUME ? MAX(texture->depth >> mipmap, 1) : texture->depth;
|
||||
}
|
||||
|
||||
int lovrTextureGetMipmapCount(Texture* texture) {
|
||||
return texture->mipmapCount;
|
||||
}
|
||||
|
||||
TextureType lovrTextureGetType(Texture* texture) {
|
||||
return texture->type;
|
||||
}
|
||||
|
||||
TextureFormat lovrTextureGetFormat(Texture* texture) {
|
||||
return texture->format;
|
||||
}
|
||||
|
||||
TextureFilter lovrTextureGetFilter(Texture* texture) {
|
||||
return texture->filter;
|
||||
}
|
||||
|
||||
void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
||||
float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.;
|
||||
lovrGpuBindTexture(texture, 0);
|
||||
|
@ -1145,10 +1056,6 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
|||
glTexParameteri(texture->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
|
||||
}
|
||||
|
||||
TextureWrap lovrTextureGetWrap(Texture* texture) {
|
||||
return texture->wrap;
|
||||
}
|
||||
|
||||
void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) {
|
||||
texture->wrap = wrap;
|
||||
lovrGpuBindTexture(texture, 0);
|
||||
|
@ -1217,39 +1124,6 @@ void lovrCanvasDestroy(void* ref) {
|
|||
lovrRelease(canvas->depth.texture);
|
||||
}
|
||||
|
||||
const Attachment* lovrCanvasGetAttachments(Canvas* canvas, int* count) {
|
||||
if (count) *count = canvas->attachmentCount;
|
||||
return canvas->attachments;
|
||||
}
|
||||
|
||||
void lovrCanvasSetAttachments(Canvas* canvas, Attachment* attachments, int count) {
|
||||
lovrAssert(count > 0, "A Canvas must have at least one attached Texture");
|
||||
lovrAssert(count <= MAX_CANVAS_ATTACHMENTS, "Only %d textures can be attached to a Canvas, got %d\n", MAX_CANVAS_ATTACHMENTS, count);
|
||||
|
||||
if (!canvas->needsAttach && count == canvas->attachmentCount && !memcmp(canvas->attachments, attachments, count * sizeof(Attachment))) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Texture* texture = attachments[i].texture;
|
||||
int width = lovrTextureGetWidth(texture, attachments[i].level);
|
||||
int height = lovrTextureGetHeight(texture, attachments[i].level);
|
||||
bool hasDepth = canvas->flags.depth.enabled;
|
||||
lovrAssert(!hasDepth || width == canvas->width, "Texture width of %d does not match Canvas width (%d)", width, canvas->width);
|
||||
lovrAssert(!hasDepth || height == canvas->height, "Texture height of %d does not match Canvas height (%d)", height, canvas->height);
|
||||
lovrAssert(texture->msaa == canvas->flags.msaa, "Texture MSAA does not match Canvas MSAA");
|
||||
lovrRetain(texture);
|
||||
}
|
||||
|
||||
for (int i = 0; i < canvas->attachmentCount; i++) {
|
||||
lovrRelease(canvas->attachments[i].texture);
|
||||
}
|
||||
|
||||
memcpy(canvas->attachments, attachments, count * sizeof(Attachment));
|
||||
canvas->attachmentCount = count;
|
||||
canvas->needsAttach = true;
|
||||
}
|
||||
|
||||
void lovrCanvasBind(Canvas* canvas, bool willDraw) {
|
||||
if (canvas) {
|
||||
lovrGpuBindFramebuffer(canvas->framebuffer);
|
||||
|
@ -1311,10 +1185,6 @@ void lovrCanvasBind(Canvas* canvas, bool willDraw) {
|
|||
canvas->needsAttach = false;
|
||||
}
|
||||
|
||||
bool lovrCanvasIsDirty(Canvas* canvas) {
|
||||
return canvas->needsAttach;
|
||||
}
|
||||
|
||||
void lovrCanvasResolve(Canvas* canvas) {
|
||||
if (!canvas->needsResolve) {
|
||||
return;
|
||||
|
@ -1357,26 +1227,6 @@ void lovrCanvasResolve(Canvas* canvas) {
|
|||
canvas->needsResolve = false;
|
||||
}
|
||||
|
||||
bool lovrCanvasIsStereo(Canvas* canvas) {
|
||||
return canvas->flags.stereo;
|
||||
}
|
||||
|
||||
int lovrCanvasGetWidth(Canvas* canvas) {
|
||||
return canvas->width;
|
||||
}
|
||||
|
||||
int lovrCanvasGetHeight(Canvas* canvas) {
|
||||
return canvas->height;
|
||||
}
|
||||
|
||||
int lovrCanvasGetMSAA(Canvas* canvas) {
|
||||
return canvas->flags.msaa;
|
||||
}
|
||||
|
||||
Texture* lovrCanvasGetDepthTexture(Canvas* canvas) {
|
||||
return canvas->depth.texture;
|
||||
}
|
||||
|
||||
TextureData* lovrCanvasNewTextureData(Canvas* canvas, int index) {
|
||||
lovrCanvasBind(canvas, false);
|
||||
|
||||
|
@ -1441,14 +1291,6 @@ void lovrBufferDestroy(void* ref) {
|
|||
#endif
|
||||
}
|
||||
|
||||
size_t lovrBufferGetSize(Buffer* buffer) {
|
||||
return buffer->size;
|
||||
}
|
||||
|
||||
BufferUsage lovrBufferGetUsage(Buffer* buffer) {
|
||||
return buffer->usage;
|
||||
}
|
||||
|
||||
void* lovrBufferMap(Buffer* buffer, size_t offset) {
|
||||
return (uint8_t*) buffer->data + offset;
|
||||
}
|
||||
|
@ -1701,23 +1543,13 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
|||
}
|
||||
|
||||
switch (uniform.type) {
|
||||
case UNIFORM_FLOAT:
|
||||
glGetUniformfv(program, location, &uniform.value.floats[offset]);
|
||||
offset += uniform.components;
|
||||
break;
|
||||
|
||||
case UNIFORM_INT:
|
||||
glGetUniformiv(program, location, &uniform.value.ints[offset]);
|
||||
offset += uniform.components;
|
||||
break;
|
||||
|
||||
case UNIFORM_MATRIX:
|
||||
glGetUniformfv(program, location, &uniform.value.floats[offset]);
|
||||
offset += uniform.components * uniform.components;
|
||||
break;
|
||||
|
||||
case UNIFORM_FLOAT: glGetUniformfv(program, location, &uniform.value.floats[offset]); break;
|
||||
case UNIFORM_INT: glGetUniformiv(program, location, &uniform.value.ints[offset]); break;
|
||||
case UNIFORM_MATRIX: glGetUniformfv(program, location, &uniform.value.floats[offset]); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
offset += uniform.components * (uniform.type == UNIFORM_MATRIX ? uniform.components : 1);
|
||||
}
|
||||
|
||||
map_set(&shader->uniformMap, uniform.name, shader->uniforms.length);
|
||||
|
@ -1773,6 +1605,7 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c
|
|||
shader->program = program;
|
||||
shader->type = SHADER_GRAPHICS;
|
||||
|
||||
// Generic attributes
|
||||
lovrGpuUseProgram(program);
|
||||
glVertexAttrib4fv(LOVR_SHADER_VERTEX_COLOR, (float[4]) { 1., 1., 1., 1. });
|
||||
glVertexAttribI4iv(LOVR_SHADER_BONES, (int[4]) { 0., 0., 0., 0. });
|
||||
|
@ -1786,9 +1619,7 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c
|
|||
map_init(&shader->attributes);
|
||||
for (int i = 0; i < attributeCount; i++) {
|
||||
char name[LOVR_MAX_ATTRIBUTE_LENGTH];
|
||||
GLint size;
|
||||
GLenum type;
|
||||
glGetActiveAttrib(program, i, LOVR_MAX_ATTRIBUTE_LENGTH, NULL, &size, &type, name);
|
||||
glGetActiveAttrib(program, i, LOVR_MAX_ATTRIBUTE_LENGTH, NULL, NULL, NULL, name);
|
||||
map_set(&shader->attributes, name, glGetAttribLocation(program, name));
|
||||
}
|
||||
|
||||
|
@ -1814,17 +1645,6 @@ Shader* lovrShaderInitCompute(Shader* shader, const char* source) {
|
|||
return shader;
|
||||
}
|
||||
|
||||
Shader* lovrShaderInitDefault(Shader* shader, DefaultShader type) {
|
||||
switch (type) {
|
||||
case SHADER_DEFAULT: return lovrShaderInitGraphics(shader, NULL, NULL);
|
||||
case SHADER_CUBE: return lovrShaderInitGraphics(shader, lovrCubeVertexShader, lovrCubeFragmentShader);
|
||||
case SHADER_PANO: return lovrShaderInitGraphics(shader, lovrCubeVertexShader, lovrPanoFragmentShader);
|
||||
case SHADER_FONT: return lovrShaderInitGraphics(shader, NULL, lovrFontFragmentShader);
|
||||
case SHADER_FILL: return lovrShaderInitGraphics(shader, lovrFillVertexShader, NULL);
|
||||
default: lovrThrow("Unknown default shader type"); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void lovrShaderDestroy(void* ref) {
|
||||
Shader* shader = ref;
|
||||
glDeleteProgram(shader->program);
|
||||
|
@ -1845,10 +1665,6 @@ void lovrShaderDestroy(void* ref) {
|
|||
map_deinit(&shader->blockMap);
|
||||
}
|
||||
|
||||
ShaderType lovrShaderGetType(Shader* shader) {
|
||||
return shader->type;
|
||||
}
|
||||
|
||||
void lovrShaderBind(Shader* shader) {
|
||||
UniformBlock* block;
|
||||
Uniform* uniform;
|
||||
|
@ -1979,104 +1795,6 @@ void lovrShaderBind(Shader* shader) {
|
|||
shader->dirty = false;
|
||||
}
|
||||
|
||||
bool lovrShaderIsDirty(Shader* shader) {
|
||||
return shader->dirty;
|
||||
}
|
||||
|
||||
int lovrShaderGetAttributeId(Shader* shader, const char* name) {
|
||||
int* id = map_get(&shader->attributes, name);
|
||||
return id ? *id : -1;
|
||||
}
|
||||
|
||||
bool lovrShaderHasUniform(Shader* shader, const char* name) {
|
||||
return map_get(&shader->uniformMap, name) != NULL;
|
||||
}
|
||||
|
||||
const Uniform* lovrShaderGetUniform(Shader* shader, const char* name) {
|
||||
int* index = map_get(&shader->uniformMap, name);
|
||||
if (!index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return &shader->uniforms.data[*index];
|
||||
}
|
||||
|
||||
static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType type, void* data, int start, int count, int size, const char* debug) {
|
||||
int* index = map_get(&shader->uniformMap, name);
|
||||
if (!index) {
|
||||
return;
|
||||
}
|
||||
|
||||
Uniform* uniform = &shader->uniforms.data[*index];
|
||||
const char* plural = (uniform->size / size) > 1 ? "s" : "";
|
||||
lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, name);
|
||||
lovrAssert((start + count) * size <= uniform->size, "Too many %s%s for uniform %s, maximum is %d", debug, plural, name, uniform->size / size);
|
||||
|
||||
void* dest = uniform->value.bytes + start * size;
|
||||
if (!uniform->dirty && !memcmp(dest, data, count * size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dest, data, count * size);
|
||||
uniform->dirty = true;
|
||||
shader->dirty = true;
|
||||
}
|
||||
|
||||
void lovrShaderSetFloats(Shader* shader, const char* name, float* data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, data, start, count, sizeof(float), "float");
|
||||
}
|
||||
|
||||
void lovrShaderSetInts(Shader* shader, const char* name, int* data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_INT, data, start, count, sizeof(int), "int");
|
||||
}
|
||||
|
||||
void lovrShaderSetMatrices(Shader* shader, const char* name, float* data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_MATRIX, data, start, count, sizeof(float), "float");
|
||||
}
|
||||
|
||||
void lovrShaderSetTextures(Shader* shader, const char* name, Texture** data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_SAMPLER, data, start, count, sizeof(Texture*), "texture");
|
||||
}
|
||||
|
||||
void lovrShaderSetImages(Shader* shader, const char* name, Image* data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_IMAGE, data, start, count, sizeof(Image), "image");
|
||||
}
|
||||
|
||||
void lovrShaderSetColor(Shader* shader, const char* name, Color color) {
|
||||
gammaCorrectColor(&color);
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, (float*) &color, 0, 4, sizeof(float), "float");
|
||||
}
|
||||
|
||||
void lovrShaderSetBlock(Shader* shader, const char* name, ShaderBlock* source, UniformAccess access) {
|
||||
int* id = map_get(&shader->blockMap, name);
|
||||
lovrAssert(id, "No shader block named '%s'", name);
|
||||
|
||||
int type = *id & 1;
|
||||
int index = *id >> 1;
|
||||
UniformBlock* block = &shader->blocks[type].data[index];
|
||||
block->access = access;
|
||||
|
||||
if (source != block->source) {
|
||||
if (source) {
|
||||
lovrAssert(block->uniforms.length == source->uniforms.length, "ShaderBlock must have same number of uniforms as block definition in Shader");
|
||||
for (int i = 0; i < block->uniforms.length; i++) {
|
||||
const Uniform* u = &block->uniforms.data[i];
|
||||
const Uniform* v = &source->uniforms.data[i];
|
||||
lovrAssert(u->type == v->type, "Shader is not compatible with ShaderBlock, check type of variable '%s'", v->name);
|
||||
lovrAssert(u->offset == v->offset, "Shader is not compatible with ShaderBlock, check order of variable '%s'", v->name);
|
||||
|
||||
// This check is disabled due to observed driver bugs with std140 layouts
|
||||
// lovrAssert(u->size == v->size, "Shader is not compatible with ShaderBlock, check count of variable '%s'", v->name);
|
||||
}
|
||||
}
|
||||
|
||||
lovrRetain(source);
|
||||
lovrRelease(block->source);
|
||||
block->source = source;
|
||||
shader->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ShaderBlock
|
||||
|
||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, vec_uniform_t* uniforms, BlockType type, BufferUsage usage) {
|
||||
|
@ -2126,62 +1844,6 @@ void lovrShaderBlockDestroy(void* ref) {
|
|||
map_deinit(&block->uniformMap);
|
||||
}
|
||||
|
||||
BlockType lovrShaderBlockGetType(ShaderBlock* block) {
|
||||
return block->type;
|
||||
}
|
||||
|
||||
// TODO use sds!
|
||||
char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, size_t* length) {
|
||||
|
||||
// Calculate
|
||||
size_t size = 0;
|
||||
size_t tab = 2;
|
||||
size += 15; // "layout(std140) "
|
||||
size += block->type == BLOCK_UNIFORM ? 7 : 6; // "uniform" || "buffer"
|
||||
size += 1; // " "
|
||||
size += strlen(blockName);
|
||||
size += 3; // " {\n"
|
||||
for (int i = 0; i < block->uniforms.length; i++) {
|
||||
size += tab;
|
||||
size += getUniformTypeLength(&block->uniforms.data[i]);
|
||||
size += 1; // " "
|
||||
size += strlen(block->uniforms.data[i].name);
|
||||
size += 2; // ";\n"
|
||||
}
|
||||
size += 3; // "};\n"
|
||||
|
||||
// Allocate
|
||||
char* code = malloc(size + 1);
|
||||
|
||||
// Concatenate
|
||||
char* s = code;
|
||||
s += sprintf(s, "layout(std140) %s %s {\n", block->type == BLOCK_UNIFORM ? "uniform" : "buffer", blockName);
|
||||
for (int i = 0; i < block->uniforms.length; i++) {
|
||||
const Uniform* uniform = &block->uniforms.data[i];
|
||||
if (uniform->count > 1) {
|
||||
s += sprintf(s, " %s %s[%d];\n", getUniformTypeName(uniform), uniform->name, uniform->count);
|
||||
} else {
|
||||
s += sprintf(s, " %s %s;\n", getUniformTypeName(uniform), uniform->name);
|
||||
}
|
||||
}
|
||||
s += sprintf(s, "};\n");
|
||||
*s = '\0';
|
||||
|
||||
*length = size;
|
||||
return code;
|
||||
}
|
||||
|
||||
const Uniform* lovrShaderBlockGetUniform(ShaderBlock* block, const char* name) {
|
||||
int* index = map_get(&block->uniformMap, name);
|
||||
if (!index) return NULL;
|
||||
|
||||
return &block->uniforms.data[*index];
|
||||
}
|
||||
|
||||
Buffer* lovrShaderBlockGetBuffer(ShaderBlock* block) {
|
||||
return block->buffer;
|
||||
}
|
||||
|
||||
// Mesh
|
||||
|
||||
Mesh* lovrMeshInit(Mesh* mesh, uint32_t count, VertexFormat format, DrawMode mode, BufferUsage usage, bool readable) {
|
||||
|
@ -2225,27 +1887,6 @@ void lovrMeshDestroy(void* ref) {
|
|||
lovrRelease(mesh->ibo);
|
||||
}
|
||||
|
||||
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute) {
|
||||
lovrAssert(!map_get(&mesh->attributes, name), "Mesh already has an attribute named '%s'", name);
|
||||
lovrAssert(attribute->divisor >= 0, "Divisor can't be negative");
|
||||
map_set(&mesh->attributes, name, *attribute);
|
||||
lovrRetain(attribute->buffer);
|
||||
mesh->dirty = true;
|
||||
}
|
||||
|
||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "No attached attribute '%s' was found", name);
|
||||
lovrAssert(attribute->buffer != mesh->vbo, "Attribute '%s' was not attached from another Mesh", name);
|
||||
lovrRelease(attribute->buffer);
|
||||
map_remove(&mesh->attributes, name);
|
||||
mesh->dirty = true;
|
||||
}
|
||||
|
||||
MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name) {
|
||||
return map_get(&mesh->attributes, name);
|
||||
}
|
||||
|
||||
void lovrMeshBind(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
||||
const char* key;
|
||||
map_iter_t iter = map_iter(&mesh->attachments);
|
||||
|
@ -2323,10 +1964,6 @@ void lovrMeshBind(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
|||
mesh->dirty = false;
|
||||
}
|
||||
|
||||
bool lovrMeshIsDirty(Mesh* mesh) {
|
||||
return mesh->dirty;
|
||||
}
|
||||
|
||||
void lovrMeshDraw(Mesh* mesh, int instances) {
|
||||
GLenum glDrawMode = convertDrawMode(mesh->mode);
|
||||
|
||||
|
@ -2350,103 +1987,3 @@ void lovrMeshDraw(Mesh* mesh, int instances) {
|
|||
|
||||
state.stats.drawCalls++;
|
||||
}
|
||||
|
||||
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh) {
|
||||
return &mesh->format;
|
||||
}
|
||||
|
||||
bool lovrMeshIsReadable(Mesh* mesh) {
|
||||
return mesh->readable;
|
||||
}
|
||||
|
||||
DrawMode lovrMeshGetDrawMode(Mesh* mesh) {
|
||||
return mesh->mode;
|
||||
}
|
||||
|
||||
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode) {
|
||||
if (mesh->mode != mode) {
|
||||
mesh->mode = mode;
|
||||
mesh->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
int lovrMeshGetVertexCount(Mesh* mesh) {
|
||||
return mesh->count;
|
||||
}
|
||||
|
||||
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
||||
return attribute->enabled;
|
||||
}
|
||||
|
||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enable) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
||||
mesh->dirty = attribute->enabled != enable;
|
||||
attribute->enabled = enable;
|
||||
}
|
||||
|
||||
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count) {
|
||||
*start = mesh->rangeStart;
|
||||
*count = mesh->rangeCount;
|
||||
}
|
||||
|
||||
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count) {
|
||||
uint32_t limit = mesh->indexCount > 0 ? mesh->indexCount : mesh->count;
|
||||
lovrAssert(start + count <= limit, "Invalid mesh draw range [%d, %d]", start + 1, start + count + 1);
|
||||
if (mesh->rangeStart != start || mesh->rangeCount != count) {
|
||||
mesh->rangeStart = start;
|
||||
mesh->rangeCount = count;
|
||||
mesh->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
Material* lovrMeshGetMaterial(Mesh* mesh) {
|
||||
return mesh->material;
|
||||
}
|
||||
|
||||
void lovrMeshSetMaterial(Mesh* mesh, Material* material) {
|
||||
if (mesh->material != material) {
|
||||
lovrRetain(material);
|
||||
lovrRelease(mesh->material);
|
||||
mesh->material = material;
|
||||
mesh->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void* lovrMeshMapVertices(Mesh* mesh, size_t offset) {
|
||||
return lovrBufferMap(mesh->vbo, offset);
|
||||
}
|
||||
|
||||
void lovrMeshFlushVertices(Mesh* mesh, size_t offset, size_t size) {
|
||||
lovrBufferFlush(mesh->vbo, offset, size);
|
||||
}
|
||||
|
||||
void* lovrMeshMapIndices(Mesh* mesh, uint32_t count, size_t indexSize, size_t offset) {
|
||||
mesh->indexSize = indexSize;
|
||||
mesh->indexCount = count;
|
||||
mesh->dirty = true;
|
||||
|
||||
if (count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mesh->indexCapacity < indexSize * count) {
|
||||
mesh->indexCapacity = nextPo2(indexSize * count);
|
||||
lovrRelease(mesh->ibo);
|
||||
mesh->ibo = lovrBufferCreate(mesh->indexCapacity, NULL, mesh->usage, mesh->readable);
|
||||
}
|
||||
|
||||
return lovrBufferMap(mesh->ibo, offset);
|
||||
}
|
||||
|
||||
void lovrMeshFlushIndices(Mesh* mesh) {
|
||||
if (mesh->indexCount > 0) {
|
||||
lovrBufferFlush(mesh->ibo, 0, mesh->indexCount * mesh->indexSize);
|
||||
}
|
||||
}
|
||||
|
||||
void* lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* indexSize) {
|
||||
return *count = mesh->indexCount, *indexSize = mesh->indexSize, lovrBufferMap(mesh->ibo, 0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
#include "graphics/shader.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "math/math.h"
|
||||
#include "resources/shaders.h"
|
||||
#include <math.h>
|
||||
|
||||
static size_t getUniformTypeLength(const Uniform* uniform) {
|
||||
size_t size = 0;
|
||||
|
||||
if (uniform->count > 1) {
|
||||
size += 2 + floor(log10(uniform->count)) + 1; // "[count]"
|
||||
}
|
||||
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_MATRIX: size += 4; break;
|
||||
case UNIFORM_FLOAT: size += uniform->components == 1 ? 5 : 4; break;
|
||||
case UNIFORM_INT: size += uniform->components == 1 ? 3 : 5; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static const char* getUniformTypeName(const Uniform* uniform) {
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_FLOAT:
|
||||
switch (uniform->components) {
|
||||
case 1: return "float";
|
||||
case 2: return "vec2";
|
||||
case 3: return "vec3";
|
||||
case 4: return "vec4";
|
||||
}
|
||||
break;
|
||||
|
||||
case UNIFORM_INT:
|
||||
switch (uniform->components) {
|
||||
case 1: return "int";
|
||||
case 2: return "ivec2";
|
||||
case 3: return "ivec3";
|
||||
case 4: return "ivec4";
|
||||
}
|
||||
break;
|
||||
|
||||
case UNIFORM_MATRIX:
|
||||
switch (uniform->components) {
|
||||
case 2: return "mat2";
|
||||
case 3: return "mat3";
|
||||
case 4: return "mat4";
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
lovrThrow("Unreachable");
|
||||
return "";
|
||||
}
|
||||
|
||||
Shader* lovrShaderInitDefault(Shader* shader, DefaultShader type) {
|
||||
switch (type) {
|
||||
case SHADER_DEFAULT: return lovrShaderInitGraphics(shader, NULL, NULL);
|
||||
case SHADER_CUBE: return lovrShaderInitGraphics(shader, lovrCubeVertexShader, lovrCubeFragmentShader);
|
||||
case SHADER_PANO: return lovrShaderInitGraphics(shader, lovrCubeVertexShader, lovrPanoFragmentShader);
|
||||
case SHADER_FONT: return lovrShaderInitGraphics(shader, NULL, lovrFontFragmentShader);
|
||||
case SHADER_FILL: return lovrShaderInitGraphics(shader, lovrFillVertexShader, NULL);
|
||||
default: lovrThrow("Unknown default shader type"); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderType lovrShaderGetType(Shader* shader) {
|
||||
return shader->type;
|
||||
}
|
||||
|
||||
bool lovrShaderIsDirty(Shader* shader) {
|
||||
return shader->dirty;
|
||||
}
|
||||
|
||||
int lovrShaderGetAttributeId(Shader* shader, const char* name) {
|
||||
int* id = map_get(&shader->attributes, name);
|
||||
return id ? *id : -1;
|
||||
}
|
||||
|
||||
bool lovrShaderHasUniform(Shader* shader, const char* name) {
|
||||
return map_get(&shader->uniformMap, name) != NULL;
|
||||
}
|
||||
|
||||
const Uniform* lovrShaderGetUniform(Shader* shader, const char* name) {
|
||||
int* index = map_get(&shader->uniformMap, name);
|
||||
if (!index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return &shader->uniforms.data[*index];
|
||||
}
|
||||
|
||||
static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType type, void* data, int start, int count, int size, const char* debug) {
|
||||
int* index = map_get(&shader->uniformMap, name);
|
||||
if (!index) {
|
||||
return;
|
||||
}
|
||||
|
||||
Uniform* uniform = &shader->uniforms.data[*index];
|
||||
const char* plural = (uniform->size / size) > 1 ? "s" : "";
|
||||
lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, name);
|
||||
lovrAssert((start + count) * size <= uniform->size, "Too many %s%s for uniform %s, maximum is %d", debug, plural, name, uniform->size / size);
|
||||
|
||||
void* dest = uniform->value.bytes + start * size;
|
||||
if (!uniform->dirty && !memcmp(dest, data, count * size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dest, data, count * size);
|
||||
uniform->dirty = true;
|
||||
shader->dirty = true;
|
||||
}
|
||||
|
||||
void lovrShaderSetFloats(Shader* shader, const char* name, float* data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, data, start, count, sizeof(float), "float");
|
||||
}
|
||||
|
||||
void lovrShaderSetInts(Shader* shader, const char* name, int* data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_INT, data, start, count, sizeof(int), "int");
|
||||
}
|
||||
|
||||
void lovrShaderSetMatrices(Shader* shader, const char* name, float* data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_MATRIX, data, start, count, sizeof(float), "float");
|
||||
}
|
||||
|
||||
void lovrShaderSetTextures(Shader* shader, const char* name, Texture** data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_SAMPLER, data, start, count, sizeof(Texture*), "texture");
|
||||
}
|
||||
|
||||
void lovrShaderSetImages(Shader* shader, const char* name, Image* data, int start, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_IMAGE, data, start, count, sizeof(Image), "image");
|
||||
}
|
||||
|
||||
void lovrShaderSetColor(Shader* shader, const char* name, Color color) {
|
||||
if (lovrGraphicsIsGammaCorrect()) {
|
||||
color.r = lovrMathGammaToLinear(color.r);
|
||||
color.g = lovrMathGammaToLinear(color.g);
|
||||
color.b = lovrMathGammaToLinear(color.b);
|
||||
}
|
||||
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, (float*) &color, 0, 4, sizeof(float), "float");
|
||||
}
|
||||
|
||||
void lovrShaderSetBlock(Shader* shader, const char* name, ShaderBlock* source, UniformAccess access) {
|
||||
int* id = map_get(&shader->blockMap, name);
|
||||
lovrAssert(id, "No shader block named '%s'", name);
|
||||
|
||||
int type = *id & 1;
|
||||
int index = *id >> 1;
|
||||
UniformBlock* block = &shader->blocks[type].data[index];
|
||||
block->access = access;
|
||||
|
||||
if (source != block->source) {
|
||||
if (source) {
|
||||
lovrAssert(block->uniforms.length == source->uniforms.length, "ShaderBlock must have same number of uniforms as block definition in Shader");
|
||||
for (int i = 0; i < block->uniforms.length; i++) {
|
||||
const Uniform* u = &block->uniforms.data[i];
|
||||
const Uniform* v = &source->uniforms.data[i];
|
||||
lovrAssert(u->type == v->type, "Shader is not compatible with ShaderBlock, check type of variable '%s'", v->name);
|
||||
lovrAssert(u->offset == v->offset, "Shader is not compatible with ShaderBlock, check order of variable '%s'", v->name);
|
||||
|
||||
// This check is disabled due to observed driver bugs with std140 layouts
|
||||
// lovrAssert(u->size == v->size, "Shader is not compatible with ShaderBlock, check count of variable '%s'", v->name);
|
||||
}
|
||||
}
|
||||
|
||||
lovrRetain(source);
|
||||
lovrRelease(block->source);
|
||||
block->source = source;
|
||||
shader->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ShaderBlock
|
||||
|
||||
BlockType lovrShaderBlockGetType(ShaderBlock* block) {
|
||||
return block->type;
|
||||
}
|
||||
|
||||
// TODO use sds!
|
||||
char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, size_t* length) {
|
||||
|
||||
// Calculate
|
||||
size_t size = 0;
|
||||
size_t tab = 2;
|
||||
size += 15; // "layout(std140) "
|
||||
size += block->type == BLOCK_UNIFORM ? 7 : 6; // "uniform" || "buffer"
|
||||
size += 1; // " "
|
||||
size += strlen(blockName);
|
||||
size += 3; // " {\n"
|
||||
for (int i = 0; i < block->uniforms.length; i++) {
|
||||
size += tab;
|
||||
size += getUniformTypeLength(&block->uniforms.data[i]);
|
||||
size += 1; // " "
|
||||
size += strlen(block->uniforms.data[i].name);
|
||||
size += 2; // ";\n"
|
||||
}
|
||||
size += 3; // "};\n"
|
||||
|
||||
// Allocate
|
||||
char* code = malloc(size + 1);
|
||||
|
||||
// Concatenate
|
||||
char* s = code;
|
||||
s += sprintf(s, "layout(std140) %s %s {\n", block->type == BLOCK_UNIFORM ? "uniform" : "buffer", blockName);
|
||||
for (int i = 0; i < block->uniforms.length; i++) {
|
||||
const Uniform* uniform = &block->uniforms.data[i];
|
||||
if (uniform->count > 1) {
|
||||
s += sprintf(s, " %s %s[%d];\n", getUniformTypeName(uniform), uniform->name, uniform->count);
|
||||
} else {
|
||||
s += sprintf(s, " %s %s;\n", getUniformTypeName(uniform), uniform->name);
|
||||
}
|
||||
}
|
||||
s += sprintf(s, "};\n");
|
||||
*s = '\0';
|
||||
|
||||
*length = size;
|
||||
return code;
|
||||
}
|
||||
|
||||
const Uniform* lovrShaderBlockGetUniform(ShaderBlock* block, const char* name) {
|
||||
int* index = map_get(&block->uniformMap, name);
|
||||
if (!index) return NULL;
|
||||
|
||||
return &block->uniforms.data[*index];
|
||||
}
|
||||
|
||||
Buffer* lovrShaderBlockGetBuffer(ShaderBlock* block) {
|
||||
return block->buffer;
|
||||
}
|
||||
|
|
@ -104,6 +104,8 @@ typedef struct {
|
|||
GPU_SHADER_FIELDS
|
||||
} Shader;
|
||||
|
||||
// Shader
|
||||
|
||||
Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const char* fragmentSource);
|
||||
Shader* lovrShaderInitCompute(Shader* shader, const char* source);
|
||||
Shader* lovrShaderInitDefault(Shader* shader, DefaultShader type);
|
||||
|
@ -125,6 +127,8 @@ void lovrShaderSetImages(Shader* shader, const char* name, Image* data, int star
|
|||
void lovrShaderSetColor(Shader* shader, const char* name, Color color);
|
||||
void lovrShaderSetBlock(Shader* shader, const char* name, ShaderBlock* block, UniformAccess access);
|
||||
|
||||
// ShaderBlock
|
||||
|
||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, vec_uniform_t* uniforms, BlockType type, BufferUsage usage);
|
||||
#define lovrShaderBlockCreate(...) lovrShaderBlockInit(lovrAlloc(ShaderBlock), __VA_ARGS__)
|
||||
void lovrShaderBlockDestroy(void* ref);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#include "graphics/texture.h"
|
||||
|
||||
int lovrTextureGetWidth(Texture* texture, int mipmap) {
|
||||
return MAX(texture->width >> mipmap, 1);
|
||||
}
|
||||
|
||||
int lovrTextureGetHeight(Texture* texture, int mipmap) {
|
||||
return MAX(texture->height >> mipmap, 1);
|
||||
}
|
||||
|
||||
int lovrTextureGetDepth(Texture* texture, int mipmap) {
|
||||
return texture->type == TEXTURE_VOLUME ? MAX(texture->depth >> mipmap, 1) : texture->depth;
|
||||
}
|
||||
|
||||
int lovrTextureGetMipmapCount(Texture* texture) {
|
||||
return texture->mipmapCount;
|
||||
}
|
||||
|
||||
TextureType lovrTextureGetType(Texture* texture) {
|
||||
return texture->type;
|
||||
}
|
||||
|
||||
TextureFormat lovrTextureGetFormat(Texture* texture) {
|
||||
return texture->format;
|
||||
}
|
||||
|
||||
TextureFilter lovrTextureGetFilter(Texture* texture) {
|
||||
return texture->filter;
|
||||
}
|
||||
|
||||
TextureWrap lovrTextureGetWrap(Texture* texture) {
|
||||
return texture->wrap;
|
||||
}
|
Loading…
Reference in New Issue