2014-09-16 14:13:27 +02:00

444 lines
11 KiB
C

#include "../GFXBackend.h"
#include "../Emgui_internal.h"
#if defined(__APPLE__)
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#elif defined(EMGUI_UNIX)
#include <GL/gl.h>
#else
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <gl/gl.h>
#endif
#include <stdlib.h>
#include <stdio.h>
/*
#define GL_CHECK(x) do { \
x; \
GLenum glerr = glGetError(); \
if (glerr != GL_NO_ERROR) { \
printf("EMGUI: OpenGL error: %d, file: %s, line: %d", glerr, __FILE__, __LINE__); \
} \
} while (0)
*/
#define GL_CHECK(x) x;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void setColor(uint32_t color)
{
// TODO: Figure out why glColor4b doesn't work here :/
glColor4f(((color >> 0) & 0xff) * 1.0f / 255.0f,
((color >> 8) & 0xff) * 1.0f / 255.0f,
((color >> 16) & 0xff) * 1.0f / 255.0f,
((color >> 24) & 0xff) * 1.0f / 255.0f);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool EMGFXBackend_create()
{
// set the background colour
glClearColor(0.0, 0.0, 0.0, 1.0);
glClearDepth(1.0);
glDisable(GL_DEPTH_TEST);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool EMGFXBackend_destroy()
{
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void EMGFXBackend_updateViewPort(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, 0, 1);
}
static GLuint texId;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
uint64_t EMGFXBackend_createFontTexture(void* fontBuffer, int width, int height)
{
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, fontBuffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return (uint64_t)texId;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
uint64_t EMGFXBackend_createTexture(void* imageBuffer, int w, int h, int comp)
{
int format = GL_RGBA;
GL_CHECK(glGenTextures(1, &texId));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, texId));
switch (comp)
{
case 1 : format = GL_ALPHA; break;
case 3 : format = GL_RGB; break;
case 4 : format = GL_RGBA; break;
}
GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, imageBuffer));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
return (uint64_t)texId;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
static EMGUI_INLINE LoadedFont* getLoadedFont()
{
return &g_loadedFonts[g_currentFont];
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void drawText(struct DrawTextCommand* commands, int fontId)
{
const LoadedFont* font = &g_loadedFonts[fontId];
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, (GLuint)font->handle);
//glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
while (commands)
{
const char* text = commands->text;
float x = (float)commands->x;
float y = (float)commands->y;
const bool flipped = commands->flipped;
setColor(commands->color);
if (font->altLookup)
{
char c = *text++;
while (c != 0)
{
int offset = c - 32;
float s0 = (float)font->altLookup[(offset * 2) + 0];
float t0 = (float)font->altLookup[(offset * 2) + 1];
float s1 = s0 + 8.0f;
float t1 = t0 + 8.0f;
float x0 = x;
float y0 = y;
float x1 = x + 8.0f;
float y1 = y + 8.0f;
s0 *= 1.0f / 128.0f;
t0 *= 1.0f / 128.0f;
s1 *= 1.0f / 128.0f;
t1 *= 1.0f / 128.0f;
glTexCoord2f(s0, t0); glVertex2f(x0, y0);
glTexCoord2f(s1, t0); glVertex2f(x1, y0);
glTexCoord2f(s1, t1); glVertex2f(x1, y1);
glTexCoord2f(s0, t1); glVertex2f(x0, y1);
c = *text++;
x += 8.0f;
}
}
else if (font->layout)
{
float s_scale = 1.0f / (float)font->width;
float t_scale = 1.0f / (float)font->height;
const int range_start = font->rangeStart;
const int range_end = font->rangeEnd;
int c = (unsigned char)*text++;
while (c != 0)
{
if (c >= range_start && c < range_end)
{
int offset = c - range_start;
EmguiFontLayout* info = &font->layout[offset];
float s0 = info->x;
float t0 = info->y;
float s1 = (float)(info->x + info->width);
float t1 = (float)(info->y + info->height);
if (flipped)
{
float x0 = x + (float)info->yoffset;
float y0 = y + (float)info->xoffset - info->xadvance;
float x1 = x0 + (float)info->height;
float y1 = y0 + (float)info->width;
s0 *= s_scale;
s1 *= s_scale;
t0 *= t_scale;
t1 *= t_scale;
glTexCoord2f(s1, t0); glVertex2f(x0, y0);
glTexCoord2f(s1, t1); glVertex2f(x1, y0);
glTexCoord2f(s0, t1); glVertex2f(x1, y1);
glTexCoord2f(s0, t0); glVertex2f(x0, y1);
y -= (float)info->xadvance;
}
else
{
float x0 = x + (float)info->xoffset;
float y0 = y + (float)info->yoffset;
float x1 = x0 + (float)info->width;
float y1 = y0 + (float)info->height;
s0 *= s_scale;
s1 *= s_scale;
t0 *= t_scale;
t1 *= t_scale;
glTexCoord2f(s0, t0); glVertex2f(x0, y0);
glTexCoord2f(s1, t0); glVertex2f(x1, y0);
glTexCoord2f(s1, t1); glVertex2f(x1, y1);
glTexCoord2f(s0, t1); glVertex2f(x0, y1);
x += (float)info->xadvance;
}
}
c = *text++;
}
}
else
{
while (*text)
{
int c = (unsigned char)*text;
if (c >= 32 && c < 128)
{
stbtt_aligned_quad q;
stbtt_GetBakedQuad((stbtt_bakedchar*)font->cData, 512,512, c-32, &x, &y, &q, 1);
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
}
++text;
}
}
commands = commands->next;
}
glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void drawFill(struct DrawFillCommand* command)
{
glEnable(GL_BLEND);
glBegin(GL_QUADS);
while (command)
{
const float x = (float)command->x;
const float y = (float)command->y;
const float w = (float)command->width;
const float h = (float)command->height;
if (command->stipple)
{
command = command->next;
continue;
}
setColor(command->color0);
glVertex2f(x, y);
glVertex2f(x + w, y);
setColor(command->color1);
glVertex2f(x + w, y + h);
glVertex2f(x, y + h);
command = command->next;
}
glEnd();
glDisable(GL_POLYGON_STIPPLE);
glDisable(GL_BLEND);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void drawFillStipple(struct DrawFillCommand* command)
{
glEnable(GL_POLYGON_STIPPLE);
glEnable(GL_BLEND);
glBegin(GL_QUADS);
while (command)
{
const float x = (float)command->x;
const float y = (float)command->y;
const float w = (float)command->width;
const float h = (float)command->height;
if (!command->stipple)
{
command = command->next;
continue;
}
setColor(command->color0);
glVertex2f(x, y);
glVertex2f(x + w, y);
setColor(command->color1);
glVertex2f(x + w, y + h);
glVertex2f(x, y + h);
command = command->next;
}
glEnd();
glDisable(GL_POLYGON_STIPPLE);
glDisable(GL_BLEND);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void drawImage(struct DrawImageCommand* command)
{
uint64_t lastTexture = command->imageId;
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, (GLuint)lastTexture);
glBegin(GL_QUADS);
// TODO: Sorting of images type up-front
while (command)
{
const float x = (float)command->x;
const float y = (float)command->y;
const float w = (float)command->width;
const float h = (float)command->height;
if (command->imageId != (int64_t)lastTexture)
{
glEnd();
glBindTexture(GL_TEXTURE_2D, (GLuint)command->imageId);
glBegin(GL_QUADS);
lastTexture = command->imageId;
}
setColor(command->color);
glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y);
glTexCoord2f(1.0f, 0.0f); glVertex2f(x + w, y);
glTexCoord2f(1.0f, 1.0f); glVertex2f(x + w, y + h);
glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y + h);
command = command->next;
}
glEnd();
glDisable(GL_TEXTURE_2D);
}
extern struct RenderData s_renderData;
extern void swapBuffers();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void EMGFXBackend_render()
{
int i = 0, layerIter = 0;
// Not sure how to handle the clears, maybe send ClearScreen flag to Emgui_end()?
glClear(GL_COLOR_BUFFER_BIT);
// prepare for primitive drawing
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
for (layerIter = 0; layerIter < EMGUI_LAYER_COUNT; ++layerIter)
{
struct DrawLayer* layer = &s_renderData.layers[layerIter];
if (layer->scissor.width > 0 && layer->scissor.height > 0)
{
glEnable(GL_SCISSOR_TEST);
glScissor(layer->scissor.x, layer->scissor.y,
layer->scissor.width, layer->scissor.height);
}
drawFill(layer->fillCommands);
drawFillStipple(layer->fillCommands);
for (i = 0; i < EMGUI_MAX_FONTS; ++i)
{
if (layer->textCommands[i])
drawText(layer->textCommands[i], i);
}
if (layer->imageCommands)
drawImage(layer->imageCommands);
if (layer->scissor.width > 0 && layer->scissor.height > 0)
{
glDisable(GL_SCISSOR_TEST);
}
}
swapBuffers();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void EMGFXBackend_setStippleMask(unsigned char* mask)
{
glPolygonStipple(mask);
}