212 lines
7.0 KiB
C
212 lines
7.0 KiB
C
#include <stdlib.h>
|
|
#include "renderer.h"
|
|
#include "log.h"
|
|
|
|
static const char gSimpleVS[] =
|
|
"attribute vec4 position;\n"
|
|
"attribute vec2 texCoords;\n"
|
|
"varying vec2 outTexCoords;\n"
|
|
"\nvoid main(void) {\n"
|
|
" outTexCoords = texCoords;\n"
|
|
" gl_Position = position;\n"
|
|
"}\n\n";
|
|
static const char gSimpleFS[] =
|
|
"precision mediump float;\n\n"
|
|
"varying vec2 outTexCoords;\n"
|
|
"uniform sampler2D texture;\n"
|
|
"\nvoid main(void) {\n"
|
|
//" gl_FragColor = texture2D(texture, outTexCoords);\n"
|
|
" gl_FragColor = texture2D(texture, outTexCoords).bgra;\n"
|
|
//" gl_FragColor = vec4(outTexCoords.x/outTexCoords.y,outTexCoords.y/outTexCoords.x, 0.0, 0.0);\n"
|
|
"}\n\n";
|
|
|
|
static void checkGlError(const char* op, int line) {
|
|
GLint error;
|
|
char *desc = NULL;
|
|
for (error = glGetError(); error; error = glGetError()) {
|
|
switch (error) {
|
|
#define E(code) case code: desc = #code; break;
|
|
E(GL_INVALID_ENUM);
|
|
E(GL_INVALID_VALUE);
|
|
E(GL_INVALID_OPERATION);
|
|
E(GL_STACK_OVERFLOW_KHR);
|
|
E(GL_STACK_UNDERFLOW_KHR);
|
|
E(GL_OUT_OF_MEMORY);
|
|
E(GL_INVALID_FRAMEBUFFER_OPERATION);
|
|
E(GL_CONTEXT_LOST_KHR);
|
|
#undef E
|
|
}
|
|
LOGE("GL: %s after %s() (line %d)", desc, op, line);
|
|
}
|
|
}
|
|
|
|
#define checkGlError(op) checkGlError(op, __LINE__)
|
|
static GLuint loadShader(GLenum shaderType, const char* pSource) {
|
|
GLuint shader = glCreateShader(shaderType);
|
|
if (shader) {
|
|
glShaderSource(shader, 1, &pSource, NULL);
|
|
glCompileShader(shader);
|
|
GLint compiled = 0;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
|
|
if (!compiled) {
|
|
GLint infoLen = 0;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
|
|
if (infoLen) {
|
|
char* buf = (char*) malloc(infoLen);
|
|
if (buf) {
|
|
glGetShaderInfoLog(shader, infoLen, NULL, buf);
|
|
LOGE("Could not compile shader %d:\n%s\n", shaderType, buf);
|
|
free(buf);
|
|
}
|
|
glDeleteShader(shader);
|
|
shader = 0;
|
|
}
|
|
}
|
|
}
|
|
return shader;
|
|
}
|
|
|
|
static GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
|
|
GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
|
|
if (!vertexShader) {
|
|
return 0;
|
|
}
|
|
|
|
GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
|
|
if (!pixelShader) {
|
|
return 0;
|
|
}
|
|
|
|
GLuint program = glCreateProgram();
|
|
if (program) {
|
|
glAttachShader(program, vertexShader);
|
|
checkGlError("glAttachShader");
|
|
glAttachShader(program, pixelShader);
|
|
checkGlError("glAttachShader");
|
|
glLinkProgram(program);
|
|
GLint linkStatus = GL_FALSE;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
|
if (linkStatus != GL_TRUE) {
|
|
GLint bufLength = 0;
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
|
|
if (bufLength) {
|
|
char* buf = (char*) malloc(bufLength);
|
|
if (buf) {
|
|
glGetProgramInfoLog(program, bufLength, NULL, buf);
|
|
LOGE("Could not link program:\n%s\n", buf);
|
|
free(buf);
|
|
}
|
|
}
|
|
glDeleteProgram(program);
|
|
program = 0;
|
|
}
|
|
}
|
|
return program;
|
|
}
|
|
|
|
struct renderer *renderer_create(void) {
|
|
struct renderer* r = calloc(1, sizeof(struct renderer));
|
|
if (r == NULL) {
|
|
LOGE("Failed to allocate renderer\n");
|
|
return NULL;
|
|
}
|
|
r->gTextureProgram = createProgram(gSimpleVS, gSimpleFS); checkGlError("glCreateProgram");
|
|
if (!r->gTextureProgram) {
|
|
LOGE("GLESv2: Unable to create shader program");
|
|
renderer_destroy(&r);
|
|
return NULL;
|
|
}
|
|
r->gvPos = (GLuint) glGetAttribLocation(r->gTextureProgram, "position"); checkGlError("glGetAttribLocation");
|
|
r->gvCoords = (GLuint) glGetAttribLocation(r->gTextureProgram, "texCoords"); checkGlError("glGetAttribLocation");
|
|
r->gvTextureSamplerHandle = (GLuint) glGetUniformLocation(r->gTextureProgram, "texture"); checkGlError("glGetAttribLocation");
|
|
return r;
|
|
}
|
|
|
|
void renderer_destroy(struct renderer** renderer) {
|
|
if (!renderer || !(*renderer)) return;
|
|
|
|
glUseProgram(0);
|
|
glDeleteProgram((*renderer)->gTextureProgram);
|
|
free(*renderer);
|
|
*renderer = NULL;
|
|
}
|
|
|
|
struct texture *texture_create(int width, int height) {
|
|
if (width <= 0 || height <= 0) return NULL;
|
|
struct texture* texture = calloc(1, sizeof(struct texture));
|
|
if (texture == NULL) {
|
|
LOGE("Failed to allocate renderer\n");
|
|
return NULL;
|
|
}
|
|
|
|
LOGD("Creating %dx%d texture", width, height);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glGenTextures(1, &texture->id);
|
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
texture->width = width;
|
|
texture->height = height;
|
|
return texture;
|
|
}
|
|
|
|
void texture_upload(struct texture *texture, void *data) {
|
|
if (!texture || !data) return;
|
|
|
|
//LOGD("Texture uploading");
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
|
|
#if 1
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->width, texture->height, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
|
#else
|
|
int h;
|
|
for (h=texture->damage.y; h<(texture->damage.y+texture->damage.height); h++) {
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, texture->damage.y, texture->width, texture->damage.height, GL_RGBA, GL_UNSIGNED_BYTE, &data[texture->damage.y * texture->width * 4]);
|
|
texture->damage.x =
|
|
texture->damage.y =
|
|
texture->damage.width =
|
|
texture->damage.height = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void texture_draw(struct renderer* renderer, struct texture *texture, float x0, float y0, float x1, float y1) {
|
|
if (!renderer || !texture) return;
|
|
//LOGD("Texture drawing");
|
|
float coords[20] = {
|
|
x0, -y0, 0.f, 0.f, 0.f,
|
|
x1, -y0, 0.f, 1.f, 0.f,
|
|
x0, -y1, 0.f, 0.f, 1.f,
|
|
x1, -y1, 0.f, 1.f, 1.f,
|
|
};
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glUseProgram(renderer->gTextureProgram); checkGlError("glUseProgram");
|
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
|
|
glVertexAttribPointer(renderer->gvPos, 3, GL_FLOAT, GL_FALSE, 20, coords); checkGlError("glVertexAttribPointer");
|
|
glVertexAttribPointer(renderer->gvCoords, 2, GL_FLOAT, GL_FALSE, 20, &coords[3]); checkGlError("glVertexAttribPointer");
|
|
glEnableVertexAttribArray(renderer->gvPos); checkGlError("glEnableVertexAttribArray");
|
|
glEnableVertexAttribArray(renderer->gvCoords); checkGlError("glEnableVertexAttribArray");
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); checkGlError("glDrawArrays");
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glUseProgram(0); checkGlError("glUseProgram");
|
|
}
|
|
|
|
void texture_destroy(struct texture** texture) {
|
|
if (!texture || !(*texture)) return;
|
|
//LOGD("Texture destroying");
|
|
|
|
glDeleteTextures(1, &(*texture)->id);
|
|
|
|
free(*texture);
|
|
*texture = NULL;
|
|
}
|