restructure main, add basic font support

This commit is contained in:
gmueller
2011-01-08 17:53:45 +01:00
parent 5a0a74ef73
commit 5112241a93
7 changed files with 759 additions and 125 deletions

View File

@ -13,6 +13,7 @@ add_executable( gremlin
main
game
Explosion
oglfont
)
# set dependencies
@ -25,7 +26,7 @@ if (WIN32)
endif(WIN32)
if(UNIX)
set(PLATFORM_LIBRARIES GL X11 Xrandr -pthread)
set(PLATFORM_LIBRARIES GL X11 Xrandr pthread asound)
endif(UNIX)
target_link_libraries(gremlin

56
src/Schedule.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Schedule.h
*
* Created on: 12.06.2010
* Author: gmueller
*/
#ifndef SCHEDULE_H_
#define SCHEDULE_H_
class Schedule {
double last;
double interval;
bool exact;
bool paused;
public:
Schedule() :
last(0.0), interval(1.0), exact(true), paused(false) {
}
void init(double now) {
last = now;
}
void setInterval(double interval) {
this->interval = interval;
}
double getInterval() {
return interval;
}
void setExact(bool exact) {
this->exact = exact;
}
void setPaused(bool paused) {
this->paused = paused;
}
bool next(double now) {
if (now > (last + interval)) {
if (exact)
last += interval;
else
last = now;
if (paused)
return false;
else
return true;
} else {
return false;
}
}
};
#endif /* SCHEDULE_H_ */

View File

@ -9,6 +9,8 @@
#include "common.h"
#include "game.h"
#include "Explosion.h"
#include "Schedule.h"
#include "oglfont.h"
GLUquadricObj *quadratic;
ENetHost *host;
@ -61,7 +63,7 @@ void setup_opengl() {
glEnable( GL_LIGHTING);
// Enable vertical sync (on cards that support it)
glfwSwapInterval(1);
glfwSwapInterval(0);
}
void draw_team(team_t *team) {
@ -456,19 +458,80 @@ void explosion_callback(double x, double y, double z) {
explosion.add(x, y, z);
}
int main(int argc, char ** argv) {
int width, height, x, y, last_x, last_y;
double time, last_time, phi = 0.0, theta = 0.0, last_player_update,
last_bomb;
GLboolean running;
int server = 0;
class Application {
public:
void initialize(int argc, char ** argv);
void update();
void shutdown();
bool isRunning();
private:
bool running;
double last_time, last_bomb; //TODO: use bomb schedule;
int last_x, last_y;
double phi, theta;
double camX, camY, camZ;
Schedule accelerate_schudule;
Schedule player_update_schudule;
game_t game;
int server;
int width, height;
//TrueTyeFont font;
oglf_font_t font;
void prepareFrame(double rx, double ry, double rz);
void loadConsoleFont();
};
void Application::loadConsoleFont() {
GLuint font_id = 0;
glGenTextures(1, &font_id);
glBindTexture(GL_TEXTURE_2D, font_id);
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Upload texture from file to texture memory
glfwLoadTexture2D("data/fonts/console.tga", 0);
oglf_load(&font, "data/fonts/console.fnt", font_id);
}
void Application::prepareFrame(double rx, double ry, double rz) {
// Get window size (may be different than the requested size)
glfwGetWindowSize(&width, &height);
height = height > 0 ? height : 1;
// Set viewport
glViewport(0, 0, width, height);
// Clear color buffer
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Select and setup the projection matrix
glMatrixMode( GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (GLfloat) width / (GLfloat) height, 1.0f, 10000.0f);
// Select and setup the modelview matrix
glMatrixMode( GL_MODELVIEW);
glLoadIdentity();
gluLookAt(camX, camY, camZ, camX + rx * 10.0f, camY + ry * 10.0f, camZ + rz
* 10.0f, 0.0f, 1.0f, 0.0f);
}
void Application::initialize(int argc, char ** argv) {
server = 0;
double time, last_player_update;
quadratic = gluNewQuadric();
gluQuadricNormals(quadratic, GLU_SMOOTH);
gluQuadricTexture(quadratic, GL_TRUE);
game_t game;
game_setup(&game);
setup_opengl();
@ -484,44 +547,56 @@ int main(int argc, char ** argv) {
team_t *team = game_team(&game, 0);
local_player = game_spawn_player(&game, team);
}
float plane_color[] = { 0.2f, 0.3f, 0.4f, 1.0f };
size_t i;
running = GL_TRUE;
last_time = glfwGetTime();
last_player_update = last_time;
last_bomb = last_time;
double camX, camY, camZ;
glfwGetMousePos(&last_x, &last_y);
while (running) {
// Get time and mouse position
time = glfwGetTime();
double dt = time - last_time;
glfwGetMousePos(&x, &y);
if (glfwGetMouseButton(GLFW_MOUSE_BUTTON_2) == GLFW_PRESS) {
phi += (x - last_x) * 0.01;
theta += (y - last_y) * -0.01;
if (theta > 1.5)
theta = 1.5;
if (theta < -1.5)
theta = -1.5;
}
last_x = x;
last_y = y;
if (local_player) {
camX = local_player->x;
camY = local_player->y;
camZ = local_player->z;
} else {
camX = 1000.0;
camY = 1000.0;
camZ = 1000.0;
}
accelerate_schudule.setExact(true);
accelerate_schudule.setInterval(0.05);
double rx = cos(phi) * cos(theta);
double ry = sin(theta);
double rz = sin(phi) * cos(theta);
double v = 50.0f * dt;
player_update_schudule.setExact(true);
player_update_schudule.setInterval(0.1);
loadConsoleFont();
}
void Application::update() {
// Get time and mouse position
double time = glfwGetTime();
double dt = time - last_time;
int x, y;
glfwGetMousePos(&x, &y);
if (glfwGetMouseButton(GLFW_MOUSE_BUTTON_2) == GLFW_PRESS) {
phi += (x - last_x) * 0.01;
theta += (y - last_y) * -0.01;
if (theta > 1.5)
theta = 1.5;
if (theta < -1.5)
theta = -1.5;
}
last_x = x;
last_y = y;
if (local_player) {
camX = local_player->x;
camY = local_player->y;
camZ = local_player->z;
} else {
camX = 1000.0;
camY = 1000.0;
camZ = 1000.0;
}
double rx = cos(phi) * cos(theta);
double ry = sin(theta);
double rz = sin(phi) * cos(theta);
if (accelerate_schudule.next(time)) {
double t = accelerate_schudule.getInterval();
double v = 50.0 * t;
if (glfwGetKey('W')) {
accelerate(&game, rx * v, ry * v, rz * v);
} else if (glfwGetKey('S')) {
@ -535,101 +610,89 @@ int main(int argc, char ** argv) {
}
if (glfwGetKey(GLFW_KEY_SPACE)) {
accelerate(&game, local_player->vx * -dt, local_player->vy * -dt,
local_player->vz * -dt);
accelerate(&game, local_player->vx * -0.1, local_player->vy * -0.1,
local_player->vz * -0.1);
}
if (glfwGetKey(GLFW_KEY_LCTRL)) {
if (time - last_bomb > 5.0) {
last_bomb = time;
drop_bomb(&game, local_player->x + rx - 20.0, local_player->y
+ ry * -20.0, local_player->z + rz * -20.0, 5.0);
}
}
if (glfwGetKey(GLFW_KEY_ENTER)) {
explosion.add(200.0, 200.0, 200.0);
}
// Get window size (may be different than the requested size)
glfwGetWindowSize(&width, &height);
height = height > 0 ? height : 1;
// Set viewport
glViewport(0, 0, width, height);
// Clear color buffer
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Select and setup the projection matrix
glMatrixMode( GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (GLfloat) width / (GLfloat) height, 1.0f,
10000.0f);
// Select and setup the modelview matrix
glMatrixMode( GL_MODELVIEW);
glLoadIdentity();
gluLookAt(camX, camY, camZ, camX + cos(phi) * cos(theta) * 10.0f, camY
+ sin(theta) * 10.0f, camZ + sin(phi) * cos(theta) * 10.0f, // View-point
0.0f, 1.0f, 0.0f); // Up-vector
service_network(&game);
if (server) {
if (time > last_player_update + 0.1) {
send_player_updates(&game);
last_player_update = time;
}
}
game_update_players(&game, dt);
game_update_bombs(&game, dt, explosion_callback);
glEnable( GL_LIGHT0);
glEnable( GL_LIGHTING);
glEnable( GL_CULL_FACE);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, plane_color);
// Draw a textured quad
glBegin( GL_QUADS);
glVertex3f(-5000.0f, 5000.0f, -5000.0f);
glVertex3f(5000.0f, 5000.0f, -5000.0f);
glVertex3f(5000.0f, 5000.0f, 5000.0f);
glVertex3f(-5000.0f, 5000.0f, 5000.0f);
glEnd();
for (i = 0; i < GAME_TEAM_COUNT; i++)
draw_team(&game.team[i]);
for (i = 0; i < GAME_PLAYER_COUNT; i++)
draw_player(&game.player[i]);
for (i = 0; i < GAME_BOMB_COUNT; i++)
draw_bomb(&game.bomb[i]);
glDisable(GL_LIGHT0);
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
explosion.update(dt * 1000.0, camX, camY, camZ);
explosion.render();
// Swap buffers
glfwSwapBuffers();
// Check if the ESC key was pressed or the window was closed
running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);
last_time = time;
}
if (glfwGetKey(GLFW_KEY_LCTRL)) {
if (time - last_bomb > 5.0) {
last_bomb = time;
drop_bomb(&game, local_player->x + rx * 20.0, local_player->y + ry
* 20.0, local_player->z + rz * 20.0, 5.0);
}
}
prepareFrame(rx, ry, rz);
glEnable( GL_LIGHT0);
glEnable( GL_LIGHTING);
glEnable( GL_CULL_FACE);
const float plane_color[] = { 0.2f, 0.3f, 0.4f, 1.0f };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, plane_color);
// Draw a textured quad
glBegin( GL_QUADS);
glVertex3f(-5000.0f, 5000.0f, -5000.0f);
glVertex3f(5000.0f, 5000.0f, -5000.0f);
glVertex3f(5000.0f, 5000.0f, 5000.0f);
glVertex3f(-5000.0f, 5000.0f, 5000.0f);
glEnd();
for (size_t i = 0; i < GAME_TEAM_COUNT; i++)
draw_team(&game.team[i]);
for (size_t i = 0; i < GAME_PLAYER_COUNT; i++)
draw_player(&game.player[i]);
for (size_t i = 0; i < GAME_BOMB_COUNT; i++)
draw_bomb(&game.bomb[i]);
glDisable(GL_LIGHT0);
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
explosion.update(dt * 1000.0, camX, camY, camZ);
explosion.render();
oglf_begin(&font, width, height);
oglf_print(&font, 40, 40, "Hello");
oglf_end();
// Swap buffers
glfwSwapBuffers();
// Check if the ESC key was pressed or the window was closed
running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);
service_network(&game);
if (server && player_update_schudule.next(time)) {
send_player_updates(&game);
}
game_update_players(&game, dt);
game_update_bombs(&game, dt, explosion_callback);
last_time = time;
}
void Application::shutdown() {
gluDeleteQuadric(quadratic);
enet_host_destroy(host);
enet_deinitialize();
oglf_destroy(&font);
// Close OpenGL window and terminate GLFW
glfwTerminate();
}
bool Application::isRunning() {
return running;
}
int main(int argc, char ** argv) {
Application app;
app.initialize(argc, argv);
while (app.isRunning())
app.update();
app.shutdown();
return 0;
}

270
src/oglfont.cpp Normal file
View File

@ -0,0 +1,270 @@
#include "oglfont.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#define GL_Y_FIX(f) (1 - (f))
static void _compile(oglf_font_t *font) {
int chr;
font->base_list = glGenLists(OGLF_MAX_ASCII);
glBindTexture(GL_TEXTURE_2D, font->fontTex);
for (chr = 0; chr < OGLF_MAX_ASCII; chr++) {
glNewList(font->base_list + chr - 1, GL_COMPILE);
if (font->chars[chr].w) {
glBegin(GL_QUADS);
glTexCoord2f(
(float) font->chars[chr].x / (float) font->w,
(float) GL_Y_FIX((font->chars[chr].y+font->chars[chr].h) / (float) font->h));
glVertex2d((float) font->chars[chr].x_ofs,
(float) font->chars[chr].h + font->chars[chr].y_ofs);
glTexCoord2f(
(float) (font->chars[chr].x + font->chars[chr].w)
/ (float) font->w,
(float) GL_Y_FIX((font->chars[chr].y + font->chars[chr].h) / (float) font->h));
glVertex2d((float) font->chars[chr].w + font->chars[chr].x_ofs,
(float) font->chars[chr].h + font->chars[chr].y_ofs);
glTexCoord2f((float) (font->chars[chr].x + font->chars[chr].w)
/ (float) font->w,
(float) GL_Y_FIX( font->chars[chr].y / (float) font->h));
glVertex2d((float) font->chars[chr].w + font->chars[chr].x_ofs,
(float) font->chars[chr].y_ofs);
glTexCoord2f((float) font->chars[chr].x / (float) font->w,
(float) GL_Y_FIX( font->chars[chr].y / (float) font->h));
glVertex2d((float) font->chars[chr].x_ofs,
(float) font->chars[chr].y_ofs);
glEnd();
glTranslatef((float) (font->chars[chr].x_advance
), 0, 0);
} else {
// if char has no width, treat it like a space
glTranslatef((float) font->base, 0, 0);
}
glEndList();
}
}
static int _starts_with(const char *buffer, const char *text) {
const char *text_ptr = text;
const char *buffer_ptr = buffer;
while (*text_ptr != 0) {
if (*text_ptr != *buffer_ptr)
return 0;
text_ptr++;
buffer_ptr++;
}
return 1;
}
static int _parse_line(oglf_font_t *font, char *buffer) {
if (_starts_with(buffer, "common")) {
int count = sscanf(buffer,
"common lineHeight=%d base=%d scaleW=%d scaleH=%d pages=%d\n",
&font->line_h, &font->base, &font->w, &font->h, &font->pages);
if (count != 5)
return 0;
} else if (_starts_with(buffer, "char ")) {
oglf_char_t temp_char;
int id;
int
count =
sscanf(
buffer,
"char id=%d x=%d y=%d width=%d height=%d xoffset=%d yoffset=%d xadvance=%d page=%d chnl=%*d\n",
&id, &temp_char.x, &temp_char.y, &temp_char.w,
&temp_char.h, &temp_char.x_ofs,
&temp_char.y_ofs, &temp_char.x_advance,
&temp_char.page);
font->chars[id] = temp_char;
if (count != 9)
return 0;
}
return 1;
}
int oglf_load(oglf_font_t *font, const char *bmf_path, unsigned int texture) {
FILE *file;
char buffer[256];
file = fopen(bmf_path, "r"); // could not open file for read
if (file == 0)
return 0;
font->chars = (oglf_char_t *) malloc(OGLF_MAX_ASCII * sizeof(oglf_char_t));
while (fgets(buffer, sizeof(buffer), file) != 0) {
int result = _parse_line(font, buffer);
if (result == 0)
return 0;
}
fclose(file); // close the source file
font->fontTex = texture;
font->scale = 1.f;
_compile(font);
return 1;
}
// calculate the approx. width of a string of text
// note: no kerning info is currently evaluated
int oglf_width(oglf_font_t *font, const char *text) {
int w, l, i;
w = 0;
l = strlen(text);
for (i = 0; i < l; i++) {
//w += font->chars[text[i]].w;
w += font->chars[text[i]].x_advance;
}
return w;
}
// destroy the charset
void oglf_destroy(oglf_font_t *font) {
glDeleteLists(font->base_list, OGLF_MAX_ASCII);
glDeleteTextures(1, &font->fontTex);
free(font->chars);
}
/*
void ogl___font_in(ogl_font *font);
void bmf___font_in(ogl_font *font) {
ogl___font_in(font);
}
*/
void oglf_begin(oglf_font_t *font, int width, int height) {
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT
| GL_TRANSFORM_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
//glNormal3f( 0.0, 0.0, 1.0);
// set projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
//int newheight = (_width / 16.0) * 9.0;
glOrtho(0.0,
(double)width,
(double)height,
0.0,
-1.0,
1.0);
// prepare model matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
//glScalef(font->scale, font->scale, 1.f);
glBindTexture(GL_TEXTURE_2D, font->fontTex);
glEnable(GL_TEXTURE_2D);
glAlphaFunc(GL_GEQUAL,0.1);
glEnable(GL_ALPHA_TEST);
}
void oglf_print_l(oglf_font_t *font, float x, float y, const char *text, int l) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(x, y, 0);
glCallLists(l, GL_UNSIGNED_BYTE, text);
glPopMatrix();
}
void oglf_end() {
glPopAttrib();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
void oglf_print(oglf_font_t *font, float x, float y, const char *text) {
oglf_print_l(font, x, y, text, strlen(text));
}
void oglf_printf(oglf_font_t *font, int x, int y, const char *fmt, ...) {
char text[OGLF_MAX_LINE], *line_start, *c;
float h;
va_list ap;
int row;
if (strlen(fmt) == 0)
return;
va_start(ap, fmt);
vsprintf(text, fmt, ap);
va_end(ap);
line_start = text;
row = 0;
h = font->h / .63f;
NextL: c = strchr(line_start, '\n');
if (c) {
row++;
oglf_print_l(font, (float) x, (float) (y - h * row), line_start, c
- line_start);
line_start = c + 1;
goto NextL;
}
oglf_print_l(font, (float) x, (float) (y - h * row), line_start, strlen(
line_start));
}
/*
#define OGLF_CENTER_TEXT(rect, txtw, ofs) ((float)((rect[ofs+_W] - txtw - rect[ofs])/2 + rect[ofs]))
// printf function which takes in account the alignment
void ogl_printf_al(oglf_font_t *font, alignment align, GLuint *rect,
const char *fmt, ...) {
char text[BMF_MAX_LINE];
va_list ap;
if (!strlen(fmt))
return;
va_start(ap, fmt);
vsprintf(text, fmt, ap);
va_end(ap);
switch (align) {
case al_left:
ogl_print(font, (float) rect[_X],
OGLF_CENTER_TEXT(rect, font->line_h, _Y), text);
break;
case al_right:
ogl_print(font, ((float) rect[_W] - ogl__width(font, text)),
OGLF_CENTER_TEXT(rect, font->line_h, _Y), text);
break;
case al_center:
ogl_print(font, OGLF_CENTER_TEXT(rect, ogl__width(font, text), _X),
OGLF_CENTER_TEXT(rect, font->line_h, _Y), text);
break;
}
}
*/

49
src/oglfont.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef OGLF_H_
#define OGLF_H_
#ifdef __cplusplus
extern "C" {
#endif
#define OGLF_MAX_ASCII 256
#define OGLF_MAX_LINE 1024
#define OGLF_MAX_PATH 256
typedef struct oglf_char_t {
unsigned int x, y, w, h;
unsigned int x_ofs, y_ofs;
unsigned int x_advance, page;
} oglf_char_t;
typedef struct oglf_kerninfo_t {
unsigned short first, second;
short kerning;
} oglf_kerninfo_t;
typedef struct oglf_font_t {
float scale;
int base, line_h, w, h, pages, kerninfo_count;
unsigned int fontTex;
int base_list;
oglf_kerninfo_t *kerninfo;
oglf_char_t *chars;
float mmat[16];
} oglf_font_t;
int oglf_load(oglf_font_t *font, const char *bmf_path, unsigned int texture);
int oglf_width(oglf_font_t *font, const char *text);
void oglf_destroy(oglf_font_t *font);
void oglf_begin(oglf_font_t *font, int width, int height);
void oglf_end();
void oglf_print(oglf_font_t *font, float x, float y, const char *text);
void oglf_printf_al(oglf_font_t *font, int align, unsigned int *rect,
const char *fmt, ...);
void oglf_printf(oglf_font_t *font, int x, int y, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif // _FONT_H_