New renderer starting to work.

Image loading still not working and font sizing is still off. Resolution is hardcoded.
This commit is contained in:
Aloshi 2012-08-29 13:53:53 -05:00
parent bff542f076
commit 0314a14849
14 changed files with 831 additions and 357 deletions

View file

@ -1,7 +1,7 @@
CC=g++
CFLAGS=-c -Wall
LDFLAGS=-lSDL -lSDL_ttf -lSDL_image -lSDL_gfx -lboost_system -lboost_filesystem
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
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=-L/opt/vc/lib -lbcm_host -lEGL -lGLESv2 -lfreetype -lSDL -lboost_system -lboost_filesystem -lfreeimage
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))
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=emulationstation

257
src/Font.cpp Normal file
View 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
View 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

View file

@ -3,9 +3,6 @@
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)
{
renderVector.push_back(comp);

View file

@ -1,14 +1,9 @@
#ifndef _RENDERER_H_
#define _RENDERER_H_
#define LAYER_COUNT 3
#define BIT(x) (1 << (x))
#include <vector>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include <string>
#include "Font.h"
class GuiComponent;
@ -18,22 +13,20 @@ namespace Renderer
void unregisterComponent(GuiComponent* comp);
void deleteAll();
void render();
bool init(int w, int h);
void deinit();
extern SDL_Surface* screen;
extern TTF_Font* font;
void render();
unsigned int getScreenWidth();
unsigned int getScreenHeight();
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
void buildGLColorArray(GLubyte* ptr, int color, unsigned int vertCount);
//drawing commands
void swapBuffers();
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 drawCenteredText(std::string text, int xOffset, int y, int color, FontSize fontsize = MEDIUM);

View file

@ -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
View 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
View 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();
}
};

View file

@ -5,6 +5,7 @@
#include <fstream>
#include <stdlib.h>
#include <SDL/SDL_joystick.h>
#include "Renderer.h"
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)
SDL_JoystickEventState(0);
Renderer::deinit();
std::string command = mLaunchCommand;
command = strreplace(command, "%ROM%", game->getBashPath());
@ -81,6 +84,8 @@ void SystemData::launchGame(GameData* game)
std::cout << "...launch terminated!\n";
Renderer::init(0, 0);
//re-enable SDL joystick events
SDL_JoystickEventState(1);
}

View file

@ -4,8 +4,6 @@
#include "GuiMenu.h"
#include <boost/filesystem.hpp>
//#define DRAWFRAMERATE
#ifdef DRAWFRAMERATE
#include <sstream>
extern float FRAMERATE;
@ -88,7 +86,7 @@ void GuiGameList::setSystemId(int id)
void GuiGameList::onRender()
{
Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0xFFFFFF);
//Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0xFFFFFF);
if(mTheme)
mTheme->render();

View file

@ -11,6 +11,8 @@
#include "../GameData.h"
#include "../FolderData.h"
#define DRAWFRAMERATE
class GuiGameList : GuiComponent
{
public:

View file

@ -1,15 +1,13 @@
#include "GuiImage.h"
#include <SDL/SDL_image.h>
#include <SDL/SDL_rotozoom.h>
#include <iostream>
#include <boost/filesystem.hpp>
int GuiImage::getWidth() { if(mSurface) return mSurface->w; else return 0; }
int GuiImage::getHeight() { if(mSurface) return mSurface->h; else return 0; }
int GuiImage::getWidth() { return mWidth; }
int GuiImage::getHeight() { return 100; }
GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int maxWidth, unsigned int maxHeight, bool resizeExact)
{
mSurface = NULL;
mTextureID = 0;
mOffsetX = offsetX;
mOffsetY = offsetY;
@ -18,6 +16,9 @@ GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int maxW
mOriginX = 0.5;
mOriginY = 0.5;
mWidth = 0;
mHeight = 0;
mTiled = false;
mMaxWidth = maxWidth;
@ -32,92 +33,96 @@ GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int maxW
GuiImage::~GuiImage()
{
if(mSurface)
SDL_FreeSurface(mSurface);
unloadImage();
}
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());
std::cerr << "File \"" << path << "\" not found!\n";
return;
}
//if we started loading something else or failed to load, don't bother resizing
if(newSurf == NULL)
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 loading image.\n";
std::cerr << "Error - could not detect filetype for image \"" << path << "\"!\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();
//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 << "File \"" << path << "\" not found!\n";
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::resizeSurface(SDL_Surface** surfRef)
void GuiImage::unloadImage()
{
if(mTiled)
return;
SDL_Surface* newSurf = *surfRef;
if(mResizeExact)
if(mTextureID)
{
double scaleX = (double)mMaxWidth / (double)newSurf->w;
double scaleY = (double)mMaxHeight / (double)newSurf->h;
std::cout << "deleting texture\n";
glDeleteTextures(1, &mTextureID);
if(scaleX == 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;
mTextureID = 0;
}
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)
@ -127,32 +132,16 @@ void GuiImage::setImage(std::string path)
mPath = path;
if(mSurface)
{
SDL_FreeSurface(mSurface);
mSurface = NULL;
}
unloadImage();
if(!path.empty())
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)
{
mOriginX = originX;
mOriginY = originY;
if(mSurface)
updateRect();
}
void GuiImage::setTiling(bool tile)
@ -166,36 +155,51 @@ void GuiImage::setTiling(bool tile)
void GuiImage::setAlpha(bool useAlpha)
{
mUseAlpha = useAlpha;
if(mSurface)
{
SDL_FreeSurface(mSurface);
mSurface = NULL;
loadImage(mPath);
}
}
bool dbg = false;
void GuiImage::onRender()
{
if(mSurface)
if(mTextureID)
{
if(mTiled)
{
SDL_Rect rect = mRect;
for(int x = 0; x < mMaxWidth / mSurface->w + 0.5; x++)
{
for(int y = 0; y < mMaxHeight / mSurface->h + 0.5; y++)
{
SDL_BlitSurface(mSurface, NULL, Renderer::screen, &rect);
rect.y += mSurface->h;
}
rect.x += mSurface->w;
rect.y = mRect.y;
}
}else{
SDL_BlitSurface(mSurface, NULL, Renderer::screen, &mRect);
}
glBindTexture(GL_TEXTURE_2D, mTextureID);
glEnable(GL_TEXTURE_2D);
GLfloat points[12];
points[0] = mOffsetX - (mWidth * mOriginX); points[1] = mOffsetY - (mHeight * mOriginY);
points[2] = mOffsetX - (mWidth * mOriginX); points[3] = mOffsetY + (mHeight * (1 - mOriginY));
points[4] = mOffsetX + (mWidth * (1 - mOriginX)); points[5] = mOffsetY - (mHeight * mOriginY);
points[6] = mOffsetX + (mWidth * (1 - mOriginX)); points[7] = mOffsetY - (mHeight * mOriginY);
points[8] = mOffsetX - (mWidth * mOriginX); points[9] = mOffsetY + (mHeight * (1 - mOriginY));
points[10] = mOffsetX + (mWidth * (1 -mOriginX)); points[11] = mOffsetY + (mHeight * (1 - mOriginY));
//std::cout << "x: " << points[0] << " y: " << points[1] << " to x: " << points[10] << " y: " << points[11] << std::endl;
//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);
}
}

View file

@ -2,9 +2,9 @@
#define _GUIIMAGE_H_
#include "../GuiComponent.h"
#include <SDL/SDL.h>
#include <SDL/SDL_thread.h>
#include <string>
#include <FreeImage.h>
#include <GLES/gl.h>
class GuiImage : public GuiComponent
{
@ -28,14 +28,14 @@ private:
bool mResizeExact, mTiled, mUseAlpha;
void loadImage(std::string path);
void resizeSurface(SDL_Surface** surfRef);
void updateRect();
void unloadImage();
std::string mPath;
SDL_Surface* mSurface;
int mOffsetX, mOffsetY;
SDL_Rect mRect;
unsigned int mWidth, mHeight;
GLuint mTextureID;
};
#endif

View file

@ -1,11 +1,10 @@
#include <iostream>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include "Renderer.h"
#include "components/GuiGameList.h"
#include "SystemData.h"
#include <boost/filesystem.hpp>
#include "components/GuiInputConfig.h"
#include <SDL.h>
bool PARSEGAMELISTONLY = 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";
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 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::screen == NULL)
if(!Renderer::init(width, height))
{
std::cerr << "Error - could not set video mode!\n";
std::cerr << " " << SDL_GetError() << "\n";
std::cerr << "\nYou may want to try using -w and -h to specify a resolution.\n";
std::cerr << "Error initializing renderer!\n";
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
@ -187,15 +175,16 @@ int main(int argc, char* argv[])
GuiComponent::processTicks(deltaTime);
Renderer::render();
SDL_Flip(Renderer::screen);
Renderer::swapBuffers();
}
Renderer::deleteAll();
Renderer::deinit();
SystemData::deleteSystems();
std::cout << "EmulationStation cleanly shutting down...\n";
TTF_Quit();
SDL_Quit();
return 0;
}