mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
289 lines
10 KiB
C
289 lines
10 KiB
C
/******************************************************************************
|
|
* Spine Runtimes Software License v2.5
|
|
*
|
|
* Copyright (c) 2013-2016, Esoteric Software
|
|
* All rights reserved.
|
|
*
|
|
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
|
* non-transferable license to use, install, execute, and perform the Spine
|
|
* Runtimes software and derivative works solely for personal or internal
|
|
* use. Without the written permission of Esoteric Software (see Section 2 of
|
|
* the Spine Software License Agreement), you may not (a) modify, translate,
|
|
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
|
* create derivative works or improvements of the Spine Runtimes or (b) remove,
|
|
* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
|
* or other intellectual property or proprietary rights notices on or in the
|
|
* Software, including any copy thereof. Redistributions in binary or source
|
|
* form must include this license and terms.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
|
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*****************************************************************************/
|
|
|
|
#include "GLUtils.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <spine/extension.h>
|
|
|
|
#include <TargetConditionals.h>
|
|
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
|
#include <OpenGLES/ES2/gl.h>
|
|
#include <OpenGLES/ES2/glext.h>
|
|
#else
|
|
#include <OpenGL/gl.h>
|
|
#include <OpenGL/glu.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#define STRINGIFY(A) #A
|
|
#define MAX_VERTICES 64000
|
|
#define MAX_INDICES 64000
|
|
|
|
const char* TWO_COLOR_TINT_VERTEX_SHADER = STRINGIFY(
|
|
attribute vec4 a_position;
|
|
attribute vec4 a_color;
|
|
attribute vec4 a_color2;
|
|
attribute vec2 a_texCoords;
|
|
|
|
\n#ifdef GL_ES\n
|
|
varying lowp vec4 v_light;
|
|
varying lowp vec4 v_dark;
|
|
varying mediump vec2 v_texCoord;
|
|
\n#else\n
|
|
varying vec4 v_light;
|
|
varying vec4 v_dark;
|
|
varying vec2 v_texCoord;
|
|
\n#endif\n
|
|
|
|
void main() {
|
|
v_light = a_color;
|
|
v_dark = a_color2;
|
|
v_texCoord = a_texCoords;
|
|
gl_Position = a_position;
|
|
}
|
|
);
|
|
|
|
const char* TWO_COLOR_TINT_FRAGMENT_SHADER = STRINGIFY(
|
|
\n#ifdef GL_ES\n
|
|
precision lowp float;
|
|
\n#endif\n
|
|
|
|
uniform sampler2D texture;
|
|
|
|
varying vec4 v_light;
|
|
varying vec4 v_dark;
|
|
varying vec2 v_texCoord;
|
|
|
|
void main() {
|
|
vec4 texColor = texture2D(texture, v_texCoord);
|
|
float alpha = texColor.a * v_light.a;
|
|
gl_FragColor.a = alpha;
|
|
gl_FragColor.rgb = ((texColor.a - 1.0) * v_dark.a + 1.0 - texColor.rgb) * v_dark.rgb + texColor.rgb * v_light.rgb;
|
|
}
|
|
);
|
|
|
|
spMesh* spMesh_create(uint32_t numVertices, uint32_t numIndices) {
|
|
spMesh* mesh = MALLOC(spMesh, 1);
|
|
mesh->vertices = MALLOC(spVertex, numVertices);
|
|
mesh->indices = MALLOC(unsigned short, numIndices);
|
|
mesh->numVertices = numVertices;
|
|
mesh->numIndices = numIndices;
|
|
mesh->numAllocatedVertices = 0;
|
|
mesh->numAllocatedIndices = 0;
|
|
return mesh;
|
|
}
|
|
|
|
void spMesh_allocatePart(spMesh* mesh, spMeshPart* part, uint32_t numVertices, uint32_t numIndices, uint32_t textureHandle, uint32_t srcBlend, uint32_t dstBlend) {
|
|
if (mesh->numVertices < mesh->numAllocatedVertices + numVertices) {
|
|
mesh->numVertices = mesh->numAllocatedVertices + numVertices;
|
|
mesh->vertices = REALLOC(mesh->vertices, spVertex, mesh->numVertices);
|
|
}
|
|
if (mesh->numIndices < mesh->numAllocatedIndices + numIndices) {
|
|
mesh->numIndices = mesh->numAllocatedIndices + numIndices;
|
|
mesh->indices = REALLOC(mesh->indices, unsigned short, mesh->numIndices);
|
|
}
|
|
|
|
part->mesh = mesh;
|
|
part->startVertex = mesh->numAllocatedVertices;
|
|
part->numIndices = numIndices;
|
|
part->startIndex = mesh->numAllocatedIndices;
|
|
part->numVertices = numVertices;
|
|
part->textureHandle = textureHandle;
|
|
part->srcBlend = srcBlend;
|
|
part->dstBlend = dstBlend;
|
|
|
|
mesh->numAllocatedVertices += numVertices;
|
|
mesh->numAllocatedIndices += numIndices;
|
|
}
|
|
|
|
void spMesh_clearParts(spMesh* mesh) {
|
|
mesh->numAllocatedIndices = 0;
|
|
mesh->numAllocatedVertices = 0;
|
|
}
|
|
|
|
void spMesh_dispose(spMesh* mesh) {
|
|
FREE(mesh->vertices);
|
|
FREE(mesh->indices);
|
|
FREE(mesh);
|
|
}
|
|
|
|
GLuint compileShader(GLenum shaderType, const char* shaderSource) {
|
|
GLuint shader = glCreateShader(shaderType);
|
|
glShaderSource(shader, 1, &shaderSource, 0);
|
|
glCompileShader(shader);
|
|
GLint status;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
if (!status) {
|
|
GLsizei length;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
|
|
if (length < 1) {
|
|
printf("Unknown error while compiling shader\n");
|
|
exit(-1);
|
|
} else {
|
|
char* log = MALLOC(char, length);
|
|
glGetShaderInfoLog(shader, length, 0, log);
|
|
printf("Error compiling shader: %s\n", log);
|
|
exit(-1);
|
|
}
|
|
}
|
|
return shader;
|
|
}
|
|
|
|
spShader* spShader_create(const char* vertexShaderSource, const char* fragmentShaderSource) {
|
|
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
|
|
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
|
|
|
|
GLuint program = glCreateProgram();
|
|
glAttachShader(program, vertexShader);
|
|
glAttachShader(program, fragmentShader);
|
|
glLinkProgram(program);
|
|
|
|
GLint status;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
|
if (!status) {
|
|
printf("Unknown error while linking program\n");
|
|
exit(-1);
|
|
}
|
|
|
|
spShader* shader = MALLOC(spShader, 1);
|
|
shader->program = program;
|
|
shader->vertexShader = vertexShader;
|
|
shader->fragmentShader = fragmentShader;
|
|
return shader;
|
|
}
|
|
|
|
void spShader_dispose(spShader* shader) {
|
|
glDeleteProgram(shader->program);
|
|
glDeleteShader(shader->vertexShader);
|
|
glDeleteShader(shader->fragmentShader);
|
|
FREE(shader);
|
|
}
|
|
|
|
spTwoColorBatcher* spTwoColorBatcher_create() {
|
|
spTwoColorBatcher* batcher = MALLOC(spTwoColorBatcher, 1);
|
|
|
|
batcher->shader = spShader_create(TWO_COLOR_TINT_VERTEX_SHADER, TWO_COLOR_TINT_FRAGMENT_SHADER);
|
|
batcher->positionAttributeLocation = glGetAttribLocation(batcher->shader->program, "a_position");
|
|
batcher->colorAttributeLocation = glGetAttribLocation(batcher->shader->program, "a_color");
|
|
batcher->color2AttributeLocation = glGetAttribLocation(batcher->shader->program, "a_color2");
|
|
batcher->texCoordsAttributeLocation = glGetAttribLocation(batcher->shader->program, "a_texCoords");
|
|
batcher->textureUniformLocation = glGetUniformLocation(batcher->shader->program, "texture");
|
|
|
|
glGenBuffers(1, &batcher->vertexBufferHandle);
|
|
glGenBuffers(1, &batcher->indexBufferHandle);
|
|
batcher->verticesBuffer = MALLOC(spVertex, MAX_VERTICES);
|
|
batcher->indicesBuffer = MALLOC(unsigned short, MAX_INDICES);
|
|
batcher->numIndices = 0;
|
|
batcher->numVertices = 0;
|
|
batcher->lastTextureHandle = -1;
|
|
batcher->lastSrcBlend = -1;
|
|
batcher->lastDstBlend = -1;
|
|
return batcher;
|
|
}
|
|
|
|
void spTwoColorBatcher_add(spTwoColorBatcher* batcher, spMeshPart mesh) {
|
|
if (batcher->numVertices + mesh.numVertices > MAX_VERTICES || batcher->numIndices + mesh.numIndices > MAX_INDICES) {
|
|
spTwoColorBatcher_flush(batcher);
|
|
}
|
|
|
|
if (batcher->lastTextureHandle != mesh.textureHandle || batcher->lastSrcBlend != mesh.srcBlend || batcher->lastDstBlend != mesh.dstBlend) {
|
|
spTwoColorBatcher_flush(batcher);
|
|
}
|
|
|
|
spVertex* vertices = &batcher->verticesBuffer[batcher->numVertices];
|
|
unsigned short* indices = &batcher->indicesBuffer[batcher->numIndices];
|
|
|
|
memcpy(vertices, &mesh.mesh->vertices[mesh.startVertex], mesh.numVertices * sizeof(spVertex));
|
|
unsigned short offset = (unsigned short)batcher->numVertices;
|
|
for (int i = 0, j = mesh.startIndex, n = mesh.numIndices; i < n; i++, j++) {
|
|
indices[i] = mesh.mesh->indices[j] + offset;
|
|
}
|
|
|
|
batcher->numIndices += mesh.numIndices;
|
|
batcher->numVertices += mesh.numVertices;
|
|
batcher->lastSrcBlend = mesh.srcBlend;
|
|
batcher->lastDstBlend = mesh.dstBlend;
|
|
batcher->lastTextureHandle = mesh.textureHandle;
|
|
}
|
|
|
|
void spTwoColorBatcher_flush(spTwoColorBatcher* batcher) {
|
|
if (batcher->numVertices == 0 || batcher->numIndices == 0)
|
|
return;
|
|
|
|
glUseProgram(batcher->shader->program);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, batcher->lastTextureHandle);
|
|
glUniform1i(batcher->textureUniformLocation, 0);
|
|
|
|
glBlendFunc(batcher->lastSrcBlend, batcher->lastDstBlend);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, batcher->vertexBufferHandle);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(spVertex) * batcher->numVertices , batcher->verticesBuffer, GL_DYNAMIC_DRAW);
|
|
|
|
glEnableVertexAttribArray(batcher->positionAttributeLocation);
|
|
glEnableVertexAttribArray(batcher->colorAttributeLocation);
|
|
glEnableVertexAttribArray(batcher->color2AttributeLocation);
|
|
glEnableVertexAttribArray(batcher->texCoordsAttributeLocation);
|
|
|
|
glVertexAttribPointer(batcher->positionAttributeLocation, 4, GL_FLOAT, GL_FALSE, sizeof(spVertex), (GLvoid*)offsetof(spVertex, x));
|
|
glVertexAttribPointer(batcher->colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(spVertex), (GLvoid*)offsetof(spVertex, color));
|
|
glVertexAttribPointer(batcher->color2AttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(spVertex), (GLvoid*)offsetof(spVertex, color2));
|
|
glVertexAttribPointer(batcher->texCoordsAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(spVertex), (GLvoid*)offsetof(spVertex, u));
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batcher->indexBufferHandle);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * batcher->numIndices, batcher->indicesBuffer, GL_STATIC_DRAW);
|
|
|
|
glDrawElements(GL_TRIANGLES, (GLsizei)batcher->numIndices, GL_UNSIGNED_SHORT, 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
glUseProgram(0);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
batcher->numIndices = 0;
|
|
batcher->numVertices = 0;
|
|
batcher->lastSrcBlend = -1;
|
|
batcher->lastDstBlend = -1;
|
|
batcher->lastTextureHandle = -1;
|
|
}
|
|
|
|
void spDisposeTwoColorBatcher(spTwoColorBatcher* batcher) {
|
|
spShader_dispose(batcher->shader);
|
|
glDeleteBuffers(1, &batcher->vertexBufferHandle);
|
|
FREE(batcher->verticesBuffer);
|
|
glDeleteBuffers(1, &batcher->indexBufferHandle);
|
|
FREE(batcher->indicesBuffer);
|
|
}
|