mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-03-06 14:27:43 +00:00
New renderer starting to work.
Image loading still not working and font sizing is still off. Resolution is hardcoded.
This commit is contained in:
parent
bff542f076
commit
0314a14849
6
Makefile
6
Makefile
|
@ -1,7 +1,7 @@
|
||||||
CC=g++
|
CC=g++
|
||||||
CFLAGS=-c -Wall
|
CFLAGS=-c -Wall -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/usr/include/freetype2 -I/usr/include/SDL -I/usr/include
|
||||||
LDFLAGS=-lSDL -lSDL_ttf -lSDL_image -lSDL_gfx -lboost_system -lboost_filesystem
|
LDFLAGS=-L/opt/vc/lib -lbcm_host -lEGL -lGLESv2 -lfreetype -lSDL -lboost_system -lboost_filesystem -lfreeimage
|
||||||
SRCSOURCES=main.cpp Renderer.cpp Renderer_draw.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp FolderData.cpp XMLReader.cpp MathExp.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp components/GuiImage.cpp components/GuiMenu.cpp components/GuiTheme.cpp pugiXML/pugixml.cpp
|
SRCSOURCES=main.cpp Renderer.cpp Renderer_init_rpi.cpp Font.cpp Renderer_draw_gl.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp FolderData.cpp XMLReader.cpp MathExp.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp components/GuiImage.cpp components/GuiMenu.cpp components/GuiTheme.cpp pugiXML/pugixml.cpp
|
||||||
SOURCES=$(addprefix src/,$(SRCSOURCES))
|
SOURCES=$(addprefix src/,$(SRCSOURCES))
|
||||||
OBJECTS=$(SOURCES:.cpp=.o)
|
OBJECTS=$(SOURCES:.cpp=.o)
|
||||||
EXECUTABLE=emulationstation
|
EXECUTABLE=emulationstation
|
||||||
|
|
257
src/Font.cpp
Normal file
257
src/Font.cpp
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
#include "Font.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include "Renderer.h"
|
||||||
|
|
||||||
|
FT_Library Font::sLibrary;
|
||||||
|
|
||||||
|
int Font::getDpiX() { return 300; }
|
||||||
|
int Font::getDpiY() { return 300; }
|
||||||
|
|
||||||
|
void Font::initLibrary()
|
||||||
|
{
|
||||||
|
if(FT_Init_FreeType(&sLibrary))
|
||||||
|
{
|
||||||
|
std::cout << "Error initializing FreeType!\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Font::Font(std::string path, int size)
|
||||||
|
{
|
||||||
|
if(FT_New_Face(sLibrary, path.c_str(), 0, &face))
|
||||||
|
{
|
||||||
|
std::cout << "Error creating font face! (path: " << path.c_str() << "\n";
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Set_Char_Size(face, 0, size * 64, getDpiX(), getDpiY());
|
||||||
|
|
||||||
|
buildAtlas();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Font::buildAtlas()
|
||||||
|
{
|
||||||
|
//find the size we should use
|
||||||
|
FT_GlyphSlot g = face->glyph;
|
||||||
|
int w = 0;
|
||||||
|
int h = 0;
|
||||||
|
|
||||||
|
/*for(int i = 32; i < 128; i++)
|
||||||
|
{
|
||||||
|
if(FT_Load_Char(face, i, FT_LOAD_RENDER))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Loading character %c failed!\n", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
w += g->bitmap.width;
|
||||||
|
h = std::max(h, g->bitmap.rows);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//GLES requires a power of two
|
||||||
|
//the max size (GL_MAX_TEXTURE_SIZE) is pretty small too, like 3300, so just force it
|
||||||
|
w = 2048;
|
||||||
|
h = 2048;
|
||||||
|
|
||||||
|
textureWidth = w;
|
||||||
|
textureHeight = h;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//create the texture
|
||||||
|
glGenTextures(1, &textureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
|
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
|
//copy the glyphs into the texture
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int maxHeight = 0;
|
||||||
|
for(int i = 32; i < 128; i++)
|
||||||
|
{
|
||||||
|
if(FT_Load_Char(face, i, FT_LOAD_RENDER))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//prints rendered texture to the console
|
||||||
|
/*std::cout << "uploading at x: " << x << ", w: " << g->bitmap.width << " h: " << g->bitmap.rows << "\n";
|
||||||
|
|
||||||
|
for(int k = 0; k < g->bitmap.rows; k++)
|
||||||
|
{
|
||||||
|
for(int j = 0; j < g->bitmap.width; j++)
|
||||||
|
{
|
||||||
|
if(g->bitmap.buffer[g->bitmap.width * k + j])
|
||||||
|
std::cout << ".";
|
||||||
|
else
|
||||||
|
std::cout << " ";
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if(x + g->bitmap.width >= textureWidth)
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
y += maxHeight;
|
||||||
|
maxHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g->bitmap.rows > maxHeight)
|
||||||
|
maxHeight = g->bitmap.rows;
|
||||||
|
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x, 0, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
|
||||||
|
|
||||||
|
|
||||||
|
charData[i].texX = x;
|
||||||
|
charData[i].texY = 0;
|
||||||
|
charData[i].texW = g->bitmap.width;
|
||||||
|
charData[i].texH = g->bitmap.rows;
|
||||||
|
charData[i].advX = g->metrics.horiAdvance >> 6;
|
||||||
|
charData[i].advY = g->advance.y >> 6;
|
||||||
|
charData[i].bearingY = g->metrics.horiBearingY >> 6;
|
||||||
|
|
||||||
|
x += g->bitmap.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
std::cout << "generated texture \"" << textureID << "\" (w: " << w << " h: " << h << ")" << std::endl;
|
||||||
|
std::cout << "(final x: " << x << " y: " << y << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Font::~Font()
|
||||||
|
{
|
||||||
|
FT_Done_Face(face);
|
||||||
|
|
||||||
|
glDeleteTextures(1, &textureID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//why these aren't in an array:
|
||||||
|
//openGL reads these in the order they are in memory
|
||||||
|
//if I use an array, it will be 4 x values then 4 y values
|
||||||
|
//it'll read XX, XX, YY instead of XY, XY, XY
|
||||||
|
struct point {
|
||||||
|
GLfloat pos0x;
|
||||||
|
GLfloat pos0y;
|
||||||
|
|
||||||
|
GLfloat pos1x;
|
||||||
|
GLfloat pos1y;
|
||||||
|
|
||||||
|
GLfloat pos2x;
|
||||||
|
GLfloat pos2y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tex {
|
||||||
|
GLfloat tex0x;
|
||||||
|
GLfloat tex0y;
|
||||||
|
|
||||||
|
GLfloat tex1x;
|
||||||
|
GLfloat tex1y;
|
||||||
|
|
||||||
|
GLfloat tex2x;
|
||||||
|
GLfloat tex2y;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Font::drawText(std::string text, int startx, int starty, int color)
|
||||||
|
{
|
||||||
|
|
||||||
|
starty += (face->height / face->units_per_EM) << 6; //(face->height / face->units_per_EM) << 6;
|
||||||
|
|
||||||
|
int pointCount = text.length() * 2;
|
||||||
|
point* points = new point[pointCount];
|
||||||
|
tex* texs = new tex[pointCount];
|
||||||
|
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
|
||||||
|
//texture atlas width/height
|
||||||
|
float tw = (float)textureWidth;
|
||||||
|
float th = (float)textureHeight;
|
||||||
|
|
||||||
|
int p = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
float x = startx;
|
||||||
|
float y = starty;
|
||||||
|
for(; p < pointCount; i++, p++)
|
||||||
|
{
|
||||||
|
int letter = text[i];
|
||||||
|
|
||||||
|
if(letter < 32 || letter >= 128)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
points[p].pos0x = x; points[p].pos0y = y + charData[letter].texH - charData[letter].bearingY;
|
||||||
|
points[p].pos1x = x + charData[letter].texW; points[p].pos1y = y - charData[letter].bearingY;
|
||||||
|
points[p].pos2x = x; points[p].pos2y = y - charData[letter].bearingY;
|
||||||
|
|
||||||
|
texs[p].tex0x = charData[letter].texX / tw; texs[p].tex0y = (charData[letter].texY + charData[letter].texH) / th;
|
||||||
|
texs[p].tex1x = (charData[letter].texX + charData[letter].texW) / tw; texs[p].tex1y = charData[letter].texY / th;
|
||||||
|
texs[p].tex2x = charData[letter].texX / tw; texs[p].tex2y = charData[letter].texY / th;
|
||||||
|
|
||||||
|
|
||||||
|
p++;
|
||||||
|
|
||||||
|
points[p].pos0x = x; points[p].pos0y = y + charData[letter].texH - charData[letter].bearingY;
|
||||||
|
points[p].pos1x = x + charData[letter].texW; points[p].pos1y = y - charData[letter].bearingY;
|
||||||
|
points[p].pos2x = x + charData[letter].texW; points[p].pos2y = y + charData[letter].texH - charData[letter].bearingY;
|
||||||
|
|
||||||
|
texs[p].tex0x = charData[letter].texX / tw; texs[p].tex0y = (charData[letter].texY + charData[letter].texH) / th;
|
||||||
|
texs[p].tex1x = (charData[letter].texX + charData[letter].texW) / tw; texs[p].tex1y = charData[letter].texY / th;
|
||||||
|
texs[p].tex2x = texs[p].tex1x; texs[p].tex2y = texs[p].tex0y;
|
||||||
|
|
||||||
|
|
||||||
|
x += charData[letter].advX;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLubyte* colors = new GLubyte[pointCount * 3 * 4];
|
||||||
|
Renderer::buildGLColorArray(colors, color, pointCount * 3);
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
glVertexPointer(2, GL_FLOAT, 0, points);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, texs);
|
||||||
|
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, pointCount * 3);
|
||||||
|
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
//not sure if this properly deletes or not
|
||||||
|
delete[] points;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Font::sizeText(std::string text, int* w, int* h)
|
||||||
|
{
|
||||||
|
if(w != NULL)
|
||||||
|
{
|
||||||
|
int cwidth = 0;
|
||||||
|
for(unsigned int i = 0; i < text.length(); i++)
|
||||||
|
{
|
||||||
|
cwidth += charData[(int)text[i]].advX;
|
||||||
|
}
|
||||||
|
|
||||||
|
*w = cwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h != NULL)
|
||||||
|
*h = (face->height / face->units_per_EM) << 6;
|
||||||
|
}
|
51
src/Font.h
Normal file
51
src/Font.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//A truetype font loader and renderer, using FreeType 2 and OpenGL.
|
||||||
|
|
||||||
|
#ifndef _FONT_H_
|
||||||
|
#define _FONT_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <GLES/gl.h>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
class Font
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void initLibrary();
|
||||||
|
|
||||||
|
Font(std::string path, int size);
|
||||||
|
~Font();
|
||||||
|
|
||||||
|
FT_Face face;
|
||||||
|
|
||||||
|
struct charPosData {
|
||||||
|
int texX;
|
||||||
|
int texY;
|
||||||
|
int texW;
|
||||||
|
int texH;
|
||||||
|
|
||||||
|
int advX;
|
||||||
|
int advY;
|
||||||
|
|
||||||
|
int bearingY;
|
||||||
|
};
|
||||||
|
|
||||||
|
charPosData charData[128];
|
||||||
|
|
||||||
|
GLuint textureID;
|
||||||
|
|
||||||
|
void drawText(std::string text, int startx, int starty, int color);
|
||||||
|
void sizeText(std::string text, int* w, int* h);
|
||||||
|
private:
|
||||||
|
|
||||||
|
static int getDpiX();
|
||||||
|
static int getDpiY();
|
||||||
|
static FT_Library sLibrary;
|
||||||
|
|
||||||
|
void buildAtlas();
|
||||||
|
|
||||||
|
int textureWidth;
|
||||||
|
int textureHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,9 +3,6 @@
|
||||||
|
|
||||||
std::vector<GuiComponent*> renderVector;
|
std::vector<GuiComponent*> renderVector;
|
||||||
|
|
||||||
unsigned int Renderer::getScreenWidth() { return Renderer::screen ? Renderer::screen->w : 640; } //1024; }
|
|
||||||
unsigned int Renderer::getScreenHeight() { return Renderer::screen ? Renderer::screen->h : 480; }
|
|
||||||
|
|
||||||
void Renderer::registerComponent(GuiComponent* comp)
|
void Renderer::registerComponent(GuiComponent* comp)
|
||||||
{
|
{
|
||||||
renderVector.push_back(comp);
|
renderVector.push_back(comp);
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
#ifndef _RENDERER_H_
|
#ifndef _RENDERER_H_
|
||||||
#define _RENDERER_H_
|
#define _RENDERER_H_
|
||||||
|
|
||||||
#define LAYER_COUNT 3
|
|
||||||
|
|
||||||
#define BIT(x) (1 << (x))
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <SDL/SDL.h>
|
|
||||||
#include <SDL/SDL_ttf.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "Font.h"
|
||||||
|
|
||||||
class GuiComponent;
|
class GuiComponent;
|
||||||
|
|
||||||
|
@ -18,22 +13,20 @@ namespace Renderer
|
||||||
void unregisterComponent(GuiComponent* comp);
|
void unregisterComponent(GuiComponent* comp);
|
||||||
void deleteAll();
|
void deleteAll();
|
||||||
|
|
||||||
void render();
|
bool init(int w, int h);
|
||||||
|
void deinit();
|
||||||
|
|
||||||
extern SDL_Surface* screen;
|
void render();
|
||||||
extern TTF_Font* font;
|
|
||||||
|
|
||||||
unsigned int getScreenWidth();
|
unsigned int getScreenWidth();
|
||||||
unsigned int getScreenHeight();
|
unsigned int getScreenHeight();
|
||||||
|
|
||||||
enum FontSize { SMALL, MEDIUM, LARGE };
|
enum FontSize { SMALL, MEDIUM, LARGE };
|
||||||
bool loadFonts();
|
|
||||||
extern bool loadedFonts;
|
|
||||||
extern TTF_Font* fonts[3]; //should be FontSize size but I don't remember the syntax
|
|
||||||
extern int fontHeight[3]; //same
|
|
||||||
int getFontHeight(FontSize size); //sometimes font size is needed before fonts have been loaded; this takes care of that
|
int getFontHeight(FontSize size); //sometimes font size is needed before fonts have been loaded; this takes care of that
|
||||||
|
void buildGLColorArray(GLubyte* ptr, int color, unsigned int vertCount);
|
||||||
|
|
||||||
//drawing commands
|
//drawing commands
|
||||||
|
void swapBuffers();
|
||||||
void drawRect(int x, int y, int w, int h, int color);
|
void drawRect(int x, int y, int w, int h, int color);
|
||||||
void drawText(std::string text, int x, int y, int color, FontSize fontsize = MEDIUM);
|
void drawText(std::string text, int x, int y, int color, FontSize fontsize = MEDIUM);
|
||||||
void drawCenteredText(std::string text, int xOffset, int y, int color, FontSize fontsize = MEDIUM);
|
void drawCenteredText(std::string text, int xOffset, int y, int color, FontSize fontsize = MEDIUM);
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
#include "Renderer.h"
|
|
||||||
#include <SDL/SDL.h>
|
|
||||||
#include <SDL/SDL_ttf.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
SDL_Surface* Renderer::screen;
|
|
||||||
bool Renderer::loadedFonts = false;
|
|
||||||
TTF_Font* Renderer::fonts[3];
|
|
||||||
int Renderer::fontHeight[3];
|
|
||||||
|
|
||||||
|
|
||||||
//a utility function to convert an int (usually defined as hex) to the SDL color struct
|
|
||||||
SDL_Color getSDLColor(int& int_color)
|
|
||||||
{
|
|
||||||
//taken off a forum post
|
|
||||||
//#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
|
||||||
SDL_Color ret={(int_color & 0x00ff0000)/0x10000,(int_color & 0x0000ff00)/0x100,(int_color & 0x000000ff),0};
|
|
||||||
//#else
|
|
||||||
// SDL_Color ret={(int_color & 0x000000ff),(int_color & 0x0000ff00)/0x100,(int_color & 0x00ff0000)/0x10000,0};
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::drawRect(int x, int y, int h, int w, int color)
|
|
||||||
{
|
|
||||||
SDL_Rect rect = {x, y, h, w};
|
|
||||||
|
|
||||||
//this is really dumb - FillRect takes a uint32, everything else uses getSDLColor
|
|
||||||
//the internal ints that we use (e.g. 0x999999) are rendered wrong
|
|
||||||
//i'm really bad at bitshifting so I don't know how to do this in a more efficient way
|
|
||||||
SDL_Color conv = getSDLColor(color);
|
|
||||||
color = SDL_MapRGB(Renderer::screen->format, conv.r, conv.g, conv.b);
|
|
||||||
|
|
||||||
SDL_FillRect(Renderer::screen, &rect, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::loadFonts()
|
|
||||||
{
|
|
||||||
std::string fontPath = "LinLibertine_R.ttf";
|
|
||||||
|
|
||||||
//if our font isn't foud, make a last-ditch effort to load a system font
|
|
||||||
if(!boost::filesystem::exists(fontPath))
|
|
||||||
{
|
|
||||||
std::cerr << "Error - " << fontPath << " font not found. Falling back to ";
|
|
||||||
fontPath = "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf";
|
|
||||||
std::cerr << fontPath << " (which may not exist).\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
int sizeArray[] = {Renderer::getScreenWidth() * 0.015, Renderer::getScreenWidth() * 0.03, Renderer::getScreenWidth() * 0.062};
|
|
||||||
|
|
||||||
|
|
||||||
//the three here should be the font count but, again, I don't remember the syntax
|
|
||||||
for(unsigned int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
TTF_Font* font = TTF_OpenFont(fontPath.c_str(), sizeArray[i]);
|
|
||||||
if(!font)
|
|
||||||
{
|
|
||||||
std::cerr << "Error - could not load font!\n";
|
|
||||||
std::cerr << TTF_GetError() << "\n";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fonts[i] = font;
|
|
||||||
TTF_SizeText(font, "HEIGHT", NULL, &fontHeight[i]); //gets the height of the string "HEIGHT" in this font (in pixels)
|
|
||||||
}
|
|
||||||
|
|
||||||
loadedFonts = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Renderer::getFontHeight(FontSize size)
|
|
||||||
{
|
|
||||||
if(!loadedFonts)
|
|
||||||
loadFonts();
|
|
||||||
|
|
||||||
return fontHeight[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::drawText(std::string text, int x, int y, int color, FontSize fontsize)
|
|
||||||
{
|
|
||||||
if(!loadedFonts)
|
|
||||||
loadFonts();
|
|
||||||
|
|
||||||
TTF_Font* font = fonts[fontsize];
|
|
||||||
|
|
||||||
//SDL_Color is a struct of four bytes, with the first three being colors. An int is four bytes.
|
|
||||||
//So, we can just pretend the int is an SDL_Color.
|
|
||||||
//SDL_Color* sdlcolor = (SDL_Color*)&color;
|
|
||||||
SDL_Color sdlcolor = getSDLColor(color);
|
|
||||||
|
|
||||||
SDL_Surface* textSurf = TTF_RenderText_Blended(font, text.c_str(), sdlcolor);
|
|
||||||
if(textSurf == NULL)
|
|
||||||
{
|
|
||||||
std::cerr << "Error - could not render text \"" << text << "\" to surface!\n";
|
|
||||||
std::cerr << TTF_GetError() << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Rect dest = {x, y};
|
|
||||||
SDL_BlitSurface(textSurf, NULL, screen, &dest);
|
|
||||||
SDL_FreeSurface(textSurf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::drawCenteredText(std::string text, int xOffset, int y, int color, FontSize fontsize)
|
|
||||||
{
|
|
||||||
if(!loadedFonts)
|
|
||||||
loadFonts();
|
|
||||||
|
|
||||||
TTF_Font* font = fonts[fontsize];
|
|
||||||
|
|
||||||
int w, h;
|
|
||||||
TTF_SizeText(font, text.c_str(), &w, &h);
|
|
||||||
|
|
||||||
int x = (int)getScreenWidth() - w;
|
|
||||||
x *= 0.5;
|
|
||||||
|
|
||||||
x += xOffset * 0.5;
|
|
||||||
|
|
||||||
drawText(text, x, y, color, fontsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
//this could probably be optimized
|
|
||||||
//draws text and ensures it's never longer than xLen
|
|
||||||
void Renderer::drawWrappedText(std::string text, int xStart, int yStart, int xLen, int color, FontSize fontsize)
|
|
||||||
{
|
|
||||||
if(!loadedFonts)
|
|
||||||
loadFonts();
|
|
||||||
|
|
||||||
TTF_Font* font = fonts[fontsize];
|
|
||||||
|
|
||||||
int y = yStart;
|
|
||||||
|
|
||||||
std::string line, word, temp;
|
|
||||||
int w, h;
|
|
||||||
size_t space, newline;
|
|
||||||
|
|
||||||
while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render
|
|
||||||
{
|
|
||||||
space = text.find(' ', 0);
|
|
||||||
if(space == std::string::npos)
|
|
||||||
space = text.length() - 1;
|
|
||||||
|
|
||||||
|
|
||||||
word = text.substr(0, space + 1);
|
|
||||||
|
|
||||||
//check if the next word contains a newline
|
|
||||||
newline = word.find('\n', 0);
|
|
||||||
if(newline != std::string::npos)
|
|
||||||
{
|
|
||||||
word = word.substr(0, newline);
|
|
||||||
text.erase(0, newline + 1);
|
|
||||||
}else{
|
|
||||||
text.erase(0, space + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
temp = line + word;
|
|
||||||
|
|
||||||
TTF_SizeText(font, temp.c_str(), &w, &h);
|
|
||||||
|
|
||||||
//if we're on the last word and it'll fit on the line, just add it to the line
|
|
||||||
if((w <= xLen && text.length() == 0) || newline != std::string::npos)
|
|
||||||
{
|
|
||||||
line = temp;
|
|
||||||
word = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//if the next line will be too long or we're on the last of the text, render it
|
|
||||||
if(w > xLen || text.length() == 0 || newline != std::string::npos)
|
|
||||||
{
|
|
||||||
//render line now
|
|
||||||
if(w > 0) //make sure it's not blank
|
|
||||||
drawText(line, xStart, y, color, fontsize);
|
|
||||||
|
|
||||||
//increment y by height and some extra padding for the next line
|
|
||||||
y += h + 4;
|
|
||||||
|
|
||||||
//move the word we skipped to the next line
|
|
||||||
line = word;
|
|
||||||
}else{
|
|
||||||
//there's still space, continue building the line
|
|
||||||
line = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
188
src/Renderer_draw_gl.cpp
Normal file
188
src/Renderer_draw_gl.cpp
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include <GLES/gl.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include "Font.h"
|
||||||
|
|
||||||
|
namespace Renderer {
|
||||||
|
bool loadedFonts = false;
|
||||||
|
|
||||||
|
unsigned int getScreenWidth() { return 1680; }
|
||||||
|
unsigned int getScreenHeight() { return 1050; }
|
||||||
|
|
||||||
|
void setColor4bArray(GLubyte* array, int color)
|
||||||
|
{
|
||||||
|
array[0] = (color & 0x00ff0000) / 0x10000;
|
||||||
|
array[1] = (color & 0x0000ff00) / 0x100;
|
||||||
|
array[2] = (color & 0x000000ff);
|
||||||
|
array[3] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildGLColorArray(GLubyte* ptr, int color, unsigned int vertCount)
|
||||||
|
{
|
||||||
|
for(unsigned int i = 0; i < vertCount; i++)
|
||||||
|
{
|
||||||
|
setColor4bArray(ptr, color);
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawRect(int x, int y, int w, int h, int color)
|
||||||
|
{
|
||||||
|
GLfloat points[12];
|
||||||
|
|
||||||
|
points[0] = x; points [1] = y;
|
||||||
|
points[2] = x; points[3] = y + h;
|
||||||
|
points[4] = x + w; points[5] = y;
|
||||||
|
|
||||||
|
points[6] = x + w; points[7] = y;
|
||||||
|
points[8] = x; points[9] = y + h;
|
||||||
|
points[10] = x + w; points[11] = y + h;
|
||||||
|
|
||||||
|
GLubyte colors[6*4];
|
||||||
|
buildGLColorArray(colors, color, 6);
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glVertexPointer(2, GL_FLOAT, 0, points);
|
||||||
|
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Font* defaultFont = NULL;
|
||||||
|
void loadFonts()
|
||||||
|
{
|
||||||
|
std::cout << "loading fonts\n";
|
||||||
|
|
||||||
|
if(defaultFont != NULL)
|
||||||
|
delete defaultFont;
|
||||||
|
|
||||||
|
defaultFont = new Font("LinLibertine_R.ttf", 12);
|
||||||
|
|
||||||
|
loadedFonts = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unloadFonts()
|
||||||
|
{
|
||||||
|
if(defaultFont)
|
||||||
|
{
|
||||||
|
delete defaultFont;
|
||||||
|
defaultFont = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedFonts = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Font* getFont(FontSize size)
|
||||||
|
{
|
||||||
|
return defaultFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getFontHeight(FontSize size)
|
||||||
|
{
|
||||||
|
if(!loadedFonts)
|
||||||
|
loadFonts();
|
||||||
|
|
||||||
|
int h;
|
||||||
|
getFont(size)->sizeText("", NULL, &h);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawText(std::string text, int x, int y, int color, FontSize font)
|
||||||
|
{
|
||||||
|
if(!loadedFonts)
|
||||||
|
loadFonts();
|
||||||
|
|
||||||
|
getFont(font)->drawText(text, x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawCenteredText(std::string text, int xOffset, int y, int color, FontSize fontsize)
|
||||||
|
{
|
||||||
|
if(!loadedFonts)
|
||||||
|
loadFonts();
|
||||||
|
|
||||||
|
Font* font = getFont(fontsize);
|
||||||
|
|
||||||
|
int w, h;
|
||||||
|
font->sizeText(text, &w, &h);
|
||||||
|
|
||||||
|
int x = (int)getScreenWidth() - w;
|
||||||
|
x *= 0.5;
|
||||||
|
|
||||||
|
x += xOffset * 0.5;
|
||||||
|
|
||||||
|
drawText(text, x, y, color, fontsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
//this could probably be optimized
|
||||||
|
//draws text and ensures it's never longer than xLen
|
||||||
|
void drawWrappedText(std::string text, int xStart, int yStart, int xLen, int color, FontSize fontsize)
|
||||||
|
{
|
||||||
|
if(!loadedFonts)
|
||||||
|
loadFonts();
|
||||||
|
|
||||||
|
Font* font = getFont(fontsize);
|
||||||
|
|
||||||
|
int y = yStart;
|
||||||
|
|
||||||
|
std::string line, word, temp;
|
||||||
|
int w, h;
|
||||||
|
size_t space, newline;
|
||||||
|
|
||||||
|
while(text.length() > 0 || !line.empty()) //while there's text or we still have text to render
|
||||||
|
{
|
||||||
|
space = text.find(' ', 0);
|
||||||
|
if(space == std::string::npos)
|
||||||
|
space = text.length() - 1;
|
||||||
|
|
||||||
|
|
||||||
|
word = text.substr(0, space + 1);
|
||||||
|
|
||||||
|
//check if the next word contains a newline
|
||||||
|
newline = word.find('\n', 0);
|
||||||
|
if(newline != std::string::npos)
|
||||||
|
{
|
||||||
|
word = word.substr(0, newline);
|
||||||
|
text.erase(0, newline + 1);
|
||||||
|
}else{
|
||||||
|
text.erase(0, space + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = line + word;
|
||||||
|
|
||||||
|
font->sizeText(temp, &w, &h);
|
||||||
|
|
||||||
|
//if we're on the last word and it'll fit on the line, just add it to the line
|
||||||
|
if((w <= xLen && text.length() == 0) || newline != std::string::npos)
|
||||||
|
{
|
||||||
|
line = temp;
|
||||||
|
word = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//if the next line will be too long or we're on the last of the text, render it
|
||||||
|
if(w > xLen || text.length() == 0 || newline != std::string::npos)
|
||||||
|
{
|
||||||
|
//render line now
|
||||||
|
if(w > 0) //make sure it's not blank
|
||||||
|
drawText(line, xStart, y, color, fontsize);
|
||||||
|
|
||||||
|
//increment y by height and some extra padding for the next line
|
||||||
|
y += h + 4;
|
||||||
|
|
||||||
|
//move the word we skipped to the next line
|
||||||
|
line = word;
|
||||||
|
}else{
|
||||||
|
//there's still space, continue building the line
|
||||||
|
line = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
178
src/Renderer_init_rpi.cpp
Normal file
178
src/Renderer_init_rpi.cpp
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
#include <bcm_host.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <bcm_host.h>
|
||||||
|
#include <GLES/gl.h>
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
#include "Font.h"
|
||||||
|
|
||||||
|
namespace Renderer
|
||||||
|
{
|
||||||
|
EGLDisplay display;
|
||||||
|
EGLSurface surface;
|
||||||
|
EGLContext context;
|
||||||
|
EGLConfig config;
|
||||||
|
|
||||||
|
static EGL_DISPMANX_WINDOW_T nativewindow;
|
||||||
|
|
||||||
|
bool createSurface()
|
||||||
|
{
|
||||||
|
std::cout << "Creating surface...\n";
|
||||||
|
|
||||||
|
|
||||||
|
DISPMANX_ELEMENT_HANDLE_T dispman_element;
|
||||||
|
DISPMANX_DISPLAY_HANDLE_T dispman_display;
|
||||||
|
DISPMANX_UPDATE_HANDLE_T dispman_update;
|
||||||
|
VC_RECT_T dst_rect;
|
||||||
|
VC_RECT_T src_rect;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
|
if(display == EGL_NO_DISPLAY)
|
||||||
|
{
|
||||||
|
std::cerr << "Error getting display!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = eglInitialize(display, NULL, NULL);
|
||||||
|
if(result == EGL_FALSE)
|
||||||
|
{
|
||||||
|
std::cerr << "Error initializing display!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
|
if(result == EGL_FALSE)
|
||||||
|
{
|
||||||
|
std::cerr << "Error binding API!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const EGLint config_attributes[] =
|
||||||
|
{
|
||||||
|
EGL_RED_SIZE, 8,
|
||||||
|
EGL_GREEN_SIZE, 8,
|
||||||
|
EGL_BLUE_SIZE, 8,
|
||||||
|
EGL_ALPHA_SIZE, 8,
|
||||||
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
GLint numConfigs;
|
||||||
|
result = eglChooseConfig(display, config_attributes, &config, 1, &numConfigs);
|
||||||
|
|
||||||
|
if(result == EGL_FALSE)
|
||||||
|
{
|
||||||
|
std::cerr << "Error choosing config!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::cout << "numConfigs: " << numConfigs << "\n";
|
||||||
|
|
||||||
|
|
||||||
|
context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL);
|
||||||
|
if(context == EGL_NO_CONTEXT)
|
||||||
|
{
|
||||||
|
std::cout << "Error: " << eglGetError() << "\n";
|
||||||
|
|
||||||
|
std::cerr << "Error getting context!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int display_width;
|
||||||
|
unsigned int display_height;
|
||||||
|
|
||||||
|
bool success = graphics_get_display_size(0, &display_width, &display_height); //0 = LCD
|
||||||
|
|
||||||
|
if(success < 0)
|
||||||
|
{
|
||||||
|
std::cerr << "Error getting display size!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Display size is " << display_width << "x" << display_height << "\n";
|
||||||
|
|
||||||
|
|
||||||
|
dst_rect.x = 0; dst_rect.y = 0;
|
||||||
|
dst_rect.width = display_width; dst_rect.height = display_height;
|
||||||
|
|
||||||
|
src_rect.x = 0; src_rect.y = 0;
|
||||||
|
src_rect.width = display_width << 16; src_rect.height = display_height << 16;
|
||||||
|
|
||||||
|
dispman_display = vc_dispmanx_display_open(0); //0 = LCD
|
||||||
|
dispman_update = vc_dispmanx_update_start(0);
|
||||||
|
|
||||||
|
dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0 /*clamp*/, DISPMANX_NO_ROTATE /*transform*/);
|
||||||
|
|
||||||
|
nativewindow.element = dispman_element;
|
||||||
|
nativewindow.width = display_width; nativewindow.height = display_height;
|
||||||
|
vc_dispmanx_update_submit_sync(dispman_update);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
surface = eglCreateWindowSurface(display, config, &nativewindow, NULL);
|
||||||
|
if(surface == EGL_NO_SURFACE)
|
||||||
|
{
|
||||||
|
std::cerr << "Error creating window surface!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = eglMakeCurrent(display, surface, surface, context);
|
||||||
|
if(result == EGL_FALSE)
|
||||||
|
{
|
||||||
|
std::cerr << "Error with eglMakeCurrent!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "success!\n";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapBuffers()
|
||||||
|
{
|
||||||
|
eglSwapBuffers(display, surface);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroySurface()
|
||||||
|
{
|
||||||
|
eglSwapBuffers(display, surface);
|
||||||
|
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
|
eglDestroySurface(display, surface);
|
||||||
|
eglDestroyContext(display, context);
|
||||||
|
eglTerminate(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init(int w, int h)
|
||||||
|
{
|
||||||
|
bcm_host_init();
|
||||||
|
bool surface = createSurface();
|
||||||
|
|
||||||
|
if(!surface)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Font::initLibrary();
|
||||||
|
|
||||||
|
glViewport(0, 0, 1680, 1050);
|
||||||
|
glOrthof(0, 1680, 1050, 0, -1.0, 1.0);
|
||||||
|
glClearColor(0.5f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unloadFonts();
|
||||||
|
void deinit()
|
||||||
|
{
|
||||||
|
unloadFonts();
|
||||||
|
destroySurface();
|
||||||
|
bcm_host_deinit();
|
||||||
|
}
|
||||||
|
};
|
|
@ -5,6 +5,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <SDL/SDL_joystick.h>
|
#include <SDL/SDL_joystick.h>
|
||||||
|
#include "Renderer.h"
|
||||||
|
|
||||||
std::vector<SystemData*> SystemData::sSystemVector;
|
std::vector<SystemData*> SystemData::sSystemVector;
|
||||||
|
|
||||||
|
@ -70,6 +71,8 @@ void SystemData::launchGame(GameData* game)
|
||||||
//suspend SDL joystick events (these'll pile up even while something else is running)
|
//suspend SDL joystick events (these'll pile up even while something else is running)
|
||||||
SDL_JoystickEventState(0);
|
SDL_JoystickEventState(0);
|
||||||
|
|
||||||
|
Renderer::deinit();
|
||||||
|
|
||||||
std::string command = mLaunchCommand;
|
std::string command = mLaunchCommand;
|
||||||
|
|
||||||
command = strreplace(command, "%ROM%", game->getBashPath());
|
command = strreplace(command, "%ROM%", game->getBashPath());
|
||||||
|
@ -81,6 +84,8 @@ void SystemData::launchGame(GameData* game)
|
||||||
|
|
||||||
std::cout << "...launch terminated!\n";
|
std::cout << "...launch terminated!\n";
|
||||||
|
|
||||||
|
Renderer::init(0, 0);
|
||||||
|
|
||||||
//re-enable SDL joystick events
|
//re-enable SDL joystick events
|
||||||
SDL_JoystickEventState(1);
|
SDL_JoystickEventState(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
#include "GuiMenu.h"
|
#include "GuiMenu.h"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
//#define DRAWFRAMERATE
|
|
||||||
|
|
||||||
#ifdef DRAWFRAMERATE
|
#ifdef DRAWFRAMERATE
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
extern float FRAMERATE;
|
extern float FRAMERATE;
|
||||||
|
@ -88,7 +86,7 @@ void GuiGameList::setSystemId(int id)
|
||||||
|
|
||||||
void GuiGameList::onRender()
|
void GuiGameList::onRender()
|
||||||
{
|
{
|
||||||
Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0xFFFFFF);
|
//Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0xFFFFFF);
|
||||||
|
|
||||||
if(mTheme)
|
if(mTheme)
|
||||||
mTheme->render();
|
mTheme->render();
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include "../GameData.h"
|
#include "../GameData.h"
|
||||||
#include "../FolderData.h"
|
#include "../FolderData.h"
|
||||||
|
|
||||||
|
#define DRAWFRAMERATE
|
||||||
|
|
||||||
class GuiGameList : GuiComponent
|
class GuiGameList : GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
#include "GuiImage.h"
|
#include "GuiImage.h"
|
||||||
#include <SDL/SDL_image.h>
|
|
||||||
#include <SDL/SDL_rotozoom.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
int GuiImage::getWidth() { if(mSurface) return mSurface->w; else return 0; }
|
int GuiImage::getWidth() { return mWidth; }
|
||||||
int GuiImage::getHeight() { if(mSurface) return mSurface->h; else return 0; }
|
int GuiImage::getHeight() { return 100; }
|
||||||
|
|
||||||
GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int maxWidth, unsigned int maxHeight, bool resizeExact)
|
GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int maxWidth, unsigned int maxHeight, bool resizeExact)
|
||||||
{
|
{
|
||||||
mSurface = NULL;
|
mTextureID = 0;
|
||||||
|
|
||||||
mOffsetX = offsetX;
|
mOffsetX = offsetX;
|
||||||
mOffsetY = offsetY;
|
mOffsetY = offsetY;
|
||||||
|
@ -18,6 +16,9 @@ GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int maxW
|
||||||
mOriginX = 0.5;
|
mOriginX = 0.5;
|
||||||
mOriginY = 0.5;
|
mOriginY = 0.5;
|
||||||
|
|
||||||
|
mWidth = 0;
|
||||||
|
mHeight = 0;
|
||||||
|
|
||||||
mTiled = false;
|
mTiled = false;
|
||||||
|
|
||||||
mMaxWidth = maxWidth;
|
mMaxWidth = maxWidth;
|
||||||
|
@ -32,92 +33,96 @@ GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int maxW
|
||||||
|
|
||||||
GuiImage::~GuiImage()
|
GuiImage::~GuiImage()
|
||||||
{
|
{
|
||||||
if(mSurface)
|
unloadImage();
|
||||||
SDL_FreeSurface(mSurface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiImage::loadImage(std::string path)
|
void GuiImage::loadImage(std::string path)
|
||||||
{
|
{
|
||||||
if(boost::filesystem::exists(path))
|
//make sure the file *exists*
|
||||||
|
if(!boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
//start loading the image
|
|
||||||
SDL_Surface* newSurf = IMG_Load(path.c_str());
|
|
||||||
|
|
||||||
//if we started loading something else or failed to load, don't bother resizing
|
|
||||||
if(newSurf == NULL)
|
|
||||||
{
|
|
||||||
std::cerr << "Error loading image.\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resizeSurface(&newSurf);
|
|
||||||
|
|
||||||
//convert it into display format for faster rendering
|
|
||||||
SDL_Surface* dispSurf;
|
|
||||||
if(mUseAlpha)
|
|
||||||
dispSurf = SDL_DisplayFormatAlpha(newSurf);
|
|
||||||
else
|
|
||||||
dispSurf = SDL_DisplayFormat(newSurf);
|
|
||||||
|
|
||||||
SDL_FreeSurface(newSurf);
|
|
||||||
newSurf = dispSurf;
|
|
||||||
|
|
||||||
|
|
||||||
//finally set the image and delete the old one
|
|
||||||
if(mSurface)
|
|
||||||
SDL_FreeSurface(mSurface);
|
|
||||||
|
|
||||||
mSurface = newSurf;
|
|
||||||
|
|
||||||
updateRect();
|
|
||||||
|
|
||||||
}else{
|
|
||||||
std::cerr << "File \"" << path << "\" not found!\n";
|
std::cerr << "File \"" << path << "\" not found!\n";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FREE_IMAGE_FORMAT format = FIF_UNKNOWN;
|
||||||
|
FIBITMAP* image = NULL;
|
||||||
|
BYTE* imageData = NULL;
|
||||||
|
unsigned int width, height;
|
||||||
|
|
||||||
|
//detect the filetype
|
||||||
|
//format = FreeImage_GetFileType(path.c_str(), 0);
|
||||||
|
if(format == FIF_UNKNOWN)
|
||||||
|
format = FreeImage_GetFIFFromFilename(path.c_str());
|
||||||
|
if(format == FIF_UNKNOWN)
|
||||||
|
{
|
||||||
|
std::cerr << "Error - could not detect filetype for image \"" << path << "\"!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//make sure we can read this filetype first, then load it
|
||||||
|
if(FreeImage_FIFSupportsReading(format))
|
||||||
|
{
|
||||||
|
std::cout << "Loading image...";
|
||||||
|
image = FreeImage_Load(format, path.c_str());
|
||||||
|
std::cout << "success\n";
|
||||||
|
}else{
|
||||||
|
std::cerr << "Error - file format reading not supported for image \"" << path << "\"!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//make sure it loaded properly
|
||||||
|
if(!image)
|
||||||
|
{
|
||||||
|
std::cerr << "Error loading image \"" << path << "\"!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imageData = FreeImage_GetBits(image);
|
||||||
|
if(!imageData)
|
||||||
|
{
|
||||||
|
std::cerr << "Error retriving bits from image \"" << path << "\"!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
width = FreeImage_GetWidth(image);
|
||||||
|
height = FreeImage_GetHeight(image);
|
||||||
|
|
||||||
|
if(!width || !height)
|
||||||
|
{
|
||||||
|
std::cerr << "Width or height are zero for image \"" << path << "\"!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//force power of two for testing
|
||||||
|
width = 512; height = 512;
|
||||||
|
|
||||||
|
//now for the openGL texture stuff
|
||||||
|
glGenTextures(1, &mTextureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mTextureID);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
|
||||||
|
|
||||||
|
mWidth = width;
|
||||||
|
mHeight = height;
|
||||||
|
|
||||||
|
//free the image data
|
||||||
|
FreeImage_Unload(image);
|
||||||
|
|
||||||
|
std::cout << "Image load successful, w: " << mWidth << " h: " << mHeight << " texID: " << mTextureID << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//enjoy this overly-complicated pointer stuff that results from splitting a function too late
|
void GuiImage::unloadImage()
|
||||||
void GuiImage::resizeSurface(SDL_Surface** surfRef)
|
|
||||||
{
|
{
|
||||||
if(mTiled)
|
if(mTextureID)
|
||||||
return;
|
|
||||||
|
|
||||||
SDL_Surface* newSurf = *surfRef;
|
|
||||||
if(mResizeExact)
|
|
||||||
{
|
{
|
||||||
double scaleX = (double)mMaxWidth / (double)newSurf->w;
|
std::cout << "deleting texture\n";
|
||||||
double scaleY = (double)mMaxHeight / (double)newSurf->h;
|
glDeleteTextures(1, &mTextureID);
|
||||||
|
|
||||||
if(scaleX == 0)
|
mTextureID = 0;
|
||||||
scaleX = scaleY;
|
|
||||||
if(scaleY == 0)
|
|
||||||
scaleY = scaleX;
|
|
||||||
|
|
||||||
SDL_Surface* resSurf = zoomSurface(newSurf, scaleX, scaleY, SMOOTHING_OFF);
|
|
||||||
SDL_FreeSurface(newSurf);
|
|
||||||
newSurf = resSurf;
|
|
||||||
}else{
|
|
||||||
if(mMaxWidth && newSurf->w > mMaxWidth)
|
|
||||||
{
|
|
||||||
double scale = (double)mMaxWidth / (double)newSurf->w;
|
|
||||||
|
|
||||||
SDL_Surface* resSurf = zoomSurface(newSurf, scale, scale, SMOOTHING_OFF);
|
|
||||||
SDL_FreeSurface(newSurf);
|
|
||||||
newSurf = resSurf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mMaxHeight && newSurf->h > mMaxHeight)
|
|
||||||
{
|
|
||||||
double scale = (double)mMaxHeight / (double)newSurf->h;
|
|
||||||
|
|
||||||
SDL_Surface* resSurf = zoomSurface(newSurf, scale, scale, SMOOTHING_OFF);
|
|
||||||
SDL_FreeSurface(newSurf);
|
|
||||||
newSurf = resSurf;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*surfRef = newSurf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiImage::setImage(std::string path)
|
void GuiImage::setImage(std::string path)
|
||||||
|
@ -127,32 +132,16 @@ void GuiImage::setImage(std::string path)
|
||||||
|
|
||||||
mPath = path;
|
mPath = path;
|
||||||
|
|
||||||
if(mSurface)
|
unloadImage();
|
||||||
{
|
|
||||||
SDL_FreeSurface(mSurface);
|
|
||||||
mSurface = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!path.empty())
|
if(!path.empty())
|
||||||
loadImage(path);
|
loadImage(path);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiImage::updateRect()
|
|
||||||
{
|
|
||||||
mRect.x = mOffsetX /*- mSurface->w*/ - (mSurface->w * mOriginX);
|
|
||||||
mRect.y = mOffsetY - (mSurface->h * mOriginY);
|
|
||||||
mRect.w = mSurface->w;
|
|
||||||
mRect.h = mSurface->h;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiImage::setOrigin(float originX, float originY)
|
void GuiImage::setOrigin(float originX, float originY)
|
||||||
{
|
{
|
||||||
mOriginX = originX;
|
mOriginX = originX;
|
||||||
mOriginY = originY;
|
mOriginY = originY;
|
||||||
|
|
||||||
if(mSurface)
|
|
||||||
updateRect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiImage::setTiling(bool tile)
|
void GuiImage::setTiling(bool tile)
|
||||||
|
@ -166,36 +155,51 @@ void GuiImage::setTiling(bool tile)
|
||||||
void GuiImage::setAlpha(bool useAlpha)
|
void GuiImage::setAlpha(bool useAlpha)
|
||||||
{
|
{
|
||||||
mUseAlpha = useAlpha;
|
mUseAlpha = useAlpha;
|
||||||
|
|
||||||
if(mSurface)
|
|
||||||
{
|
|
||||||
SDL_FreeSurface(mSurface);
|
|
||||||
mSurface = NULL;
|
|
||||||
loadImage(mPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dbg = false;
|
|
||||||
|
|
||||||
void GuiImage::onRender()
|
void GuiImage::onRender()
|
||||||
{
|
{
|
||||||
if(mSurface)
|
if(mTextureID)
|
||||||
{
|
{
|
||||||
if(mTiled)
|
glBindTexture(GL_TEXTURE_2D, mTextureID);
|
||||||
{
|
glEnable(GL_TEXTURE_2D);
|
||||||
SDL_Rect rect = mRect;
|
|
||||||
for(int x = 0; x < mMaxWidth / mSurface->w + 0.5; x++)
|
|
||||||
{
|
GLfloat points[12];
|
||||||
for(int y = 0; y < mMaxHeight / mSurface->h + 0.5; y++)
|
points[0] = mOffsetX - (mWidth * mOriginX); points[1] = mOffsetY - (mHeight * mOriginY);
|
||||||
{
|
points[2] = mOffsetX - (mWidth * mOriginX); points[3] = mOffsetY + (mHeight * (1 - mOriginY));
|
||||||
SDL_BlitSurface(mSurface, NULL, Renderer::screen, &rect);
|
points[4] = mOffsetX + (mWidth * (1 - mOriginX)); points[5] = mOffsetY - (mHeight * mOriginY);
|
||||||
rect.y += mSurface->h;
|
|
||||||
}
|
points[6] = mOffsetX + (mWidth * (1 - mOriginX)); points[7] = mOffsetY - (mHeight * mOriginY);
|
||||||
rect.x += mSurface->w;
|
points[8] = mOffsetX - (mWidth * mOriginX); points[9] = mOffsetY + (mHeight * (1 - mOriginY));
|
||||||
rect.y = mRect.y;
|
points[10] = mOffsetX + (mWidth * (1 -mOriginX)); points[11] = mOffsetY + (mHeight * (1 - mOriginY));
|
||||||
}
|
|
||||||
}else{
|
//std::cout << "x: " << points[0] << " y: " << points[1] << " to x: " << points[10] << " y: " << points[11] << std::endl;
|
||||||
SDL_BlitSurface(mSurface, NULL, Renderer::screen, &mRect);
|
//std::cout << "(w: " << mWidth << " h: " << mHeight << ")" << std::endl;
|
||||||
}
|
|
||||||
|
GLfloat texs[12];
|
||||||
|
texs[0] = 0; texs[1] = 0;
|
||||||
|
texs[2] = 0; texs[3] = 1;
|
||||||
|
texs[4] = 1; texs[5] = 0;
|
||||||
|
|
||||||
|
texs[6] = 1; texs[7] = 0;
|
||||||
|
texs[8] = 0; texs[9] = 1;
|
||||||
|
texs[10] = 1; texs[11] = 1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
|
glVertexPointer(2, GL_FLOAT, 0, points);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, texs);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
#define _GUIIMAGE_H_
|
#define _GUIIMAGE_H_
|
||||||
|
|
||||||
#include "../GuiComponent.h"
|
#include "../GuiComponent.h"
|
||||||
#include <SDL/SDL.h>
|
|
||||||
#include <SDL/SDL_thread.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <FreeImage.h>
|
||||||
|
#include <GLES/gl.h>
|
||||||
|
|
||||||
class GuiImage : public GuiComponent
|
class GuiImage : public GuiComponent
|
||||||
{
|
{
|
||||||
|
@ -28,14 +28,14 @@ private:
|
||||||
bool mResizeExact, mTiled, mUseAlpha;
|
bool mResizeExact, mTiled, mUseAlpha;
|
||||||
|
|
||||||
void loadImage(std::string path);
|
void loadImage(std::string path);
|
||||||
void resizeSurface(SDL_Surface** surfRef);
|
void unloadImage();
|
||||||
void updateRect();
|
|
||||||
|
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
|
|
||||||
SDL_Surface* mSurface;
|
|
||||||
int mOffsetX, mOffsetY;
|
int mOffsetX, mOffsetY;
|
||||||
SDL_Rect mRect;
|
unsigned int mWidth, mHeight;
|
||||||
|
|
||||||
|
GLuint mTextureID;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
29
src/main.cpp
29
src/main.cpp
|
@ -1,11 +1,10 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <SDL/SDL.h>
|
|
||||||
#include <SDL/SDL_ttf.h>
|
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "components/GuiGameList.h"
|
#include "components/GuiGameList.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include "components/GuiInputConfig.h"
|
#include "components/GuiInputConfig.h"
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
bool PARSEGAMELISTONLY = false;
|
bool PARSEGAMELISTONLY = false;
|
||||||
bool IGNOREGAMELIST = false;
|
bool IGNOREGAMELIST = false;
|
||||||
|
@ -29,13 +28,9 @@ int main(int argc, char* argv[])
|
||||||
std::cerr << "Are you in the 'video' and 'input' groups? Are you running with X closed?\n";
|
std::cerr << "Are you in the 'video' and 'input' groups? Are you running with X closed?\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(TTF_Init() != 0)
|
|
||||||
{
|
|
||||||
std::cerr << "Error - could not initialize SDL_ttf!\n";
|
|
||||||
std::cerr << " " << TTF_GetError() << "\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
SDL_Surface* sdlScreen = SDL_SetVideoMode(1, 1, 0, SDL_SWSURFACE);
|
||||||
|
std::cout << "Fake SDL window is " << sdlScreen->w << "x" << sdlScreen->h << "\n";
|
||||||
|
|
||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
|
@ -61,21 +56,14 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::screen = SDL_SetVideoMode(width, height, 16, SDL_SWSURFACE); //| SDL_FULLSCREEN);
|
if(!Renderer::init(width, height))
|
||||||
|
|
||||||
if(Renderer::screen == NULL)
|
|
||||||
{
|
{
|
||||||
std::cerr << "Error - could not set video mode!\n";
|
std::cerr << "Error initializing renderer!\n";
|
||||||
std::cerr << " " << SDL_GetError() << "\n";
|
|
||||||
std::cerr << "\nYou may want to try using -w and -h to specify a resolution.\n";
|
|
||||||
return 1;
|
return 1;
|
||||||
}else{
|
|
||||||
std::cout << "Video mode is " << Renderer::screen->w << "x" << Renderer::screen->h << "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_ShowCursor(false);
|
|
||||||
SDL_JoystickEventState(SDL_ENABLE);
|
|
||||||
|
|
||||||
|
SDL_JoystickEventState(SDL_ENABLE);
|
||||||
|
|
||||||
|
|
||||||
//make sure the config directory exists
|
//make sure the config directory exists
|
||||||
|
@ -187,15 +175,16 @@ int main(int argc, char* argv[])
|
||||||
GuiComponent::processTicks(deltaTime);
|
GuiComponent::processTicks(deltaTime);
|
||||||
|
|
||||||
Renderer::render();
|
Renderer::render();
|
||||||
SDL_Flip(Renderer::screen);
|
Renderer::swapBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Renderer::deleteAll();
|
Renderer::deleteAll();
|
||||||
|
Renderer::deinit();
|
||||||
SystemData::deleteSystems();
|
SystemData::deleteSystems();
|
||||||
|
|
||||||
std::cout << "EmulationStation cleanly shutting down...\n";
|
std::cout << "EmulationStation cleanly shutting down...\n";
|
||||||
|
|
||||||
TTF_Quit();
|
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue