⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 app_shell.cpp

📁 国外游戏开发者杂志2003年第七期配套代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
  Warning... this App_Shell class is not intended for serious
  shipping games.  It contains whatever I needed to do in order
  to get things running as quickly and simply as possible.
  It leaks memory, because I tend not to bother with cleanup.
  Also it has some O(n) functions that could be O(k).  So if
  you plan to use this in something else, you should review
  it and fix whatever you perceive to be an issue.
*/
  
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <float.h>

#include "os_specific_opengl_headers.h"

#include <gl/glu.h>

#include "jpeg_load.h"
#include "glext.h"

#include "../framework.h"

App_Shell *app_shell;

// @Cleanup: I would like to ditch these globals at some point.
static HDC global_dc = 0;
static HGLRC global_gl_rc;
static HPALETTE global_palette = NULL;
static HINSTANCE global_hinstance;
static LARGE_INTEGER global_base_time; // @Refactor: Not require this?
bool app_is_active = false;

struct Loaded_Texture_Record {
    char *name;
    int texture_handle;
};

struct Font_Character_Info {
    float u0, v0, u1, v1;
    float a, b, advance;
};

LRESULT CALLBACK WindowProc(HWND    hWnd,
							UINT    message,
							WPARAM  wParam,
							LPARAM  lParam);

static LARGE_INTEGER get_time_reading() {
    LARGE_INTEGER freq;
    LARGE_INTEGER time;

    BOOL ok = QueryPerformanceFrequency(&freq);
    assert(ok == TRUE);

    freq.QuadPart = freq.QuadPart / 1000;

    ok = QueryPerformanceCounter(&time);
    assert(ok == TRUE);

    time.QuadPart = time.QuadPart / freq.QuadPart;

	return time;
}

void add_letter_quad(Font *font, Font_Character_Info *info, float xs, float ys, float iw) {
    float u0 = info->u0;
    float u1 = info->u1;

    float npix = (u1 - u0) * iw;
    float w = npix;

    float h = font->character_height;

    glTexCoord2f(u0, info->v0);
    glVertex2f(xs, ys);

    glTexCoord2f(u1, info->v0);
    glVertex2f(xs+w, ys);

    glTexCoord2f(u1, info->v1);
    glVertex2f(xs+w, ys+h);

    glTexCoord2f(u0, info->v1);
    glVertex2f(xs, ys+h);
}

inline int remap_letter(Font *font, unsigned int letter) {
    if (letter < font->character_range_low) return -1;
    if (letter > font->character_range_high) return -1;
    letter -= font->character_range_low;
    return letter;
}

float Font::get_string_width_in_pixels(char *s) {
    float sum = 0;
    while (*s) {
        int letter = remap_letter(this, *s);
        if (letter != -1) {
            Font_Character_Info *info = &character_info[letter];
            sum += info->advance;
        }

        s++;
    }

    return sum;
}

void App_Shell::draw_text(Font *font, float xs, float ys, char *s, float cr, float cg, float cb, float ca,
                          float max_width) {
    int len = strlen(s);

    glBegin(GL_QUADS);

    xs -= 0.5f;
    glColor4f(cr, cg, cb, ca);

    float iw = (float)font->texture_width;
    float width = 0;

    int i;
    for (i = 0; i < len; i++) {
        int letter = remap_letter(font, s[i]);
        if (letter == -1) continue;

        Font_Character_Info *info = &font->character_info[letter];
        if (max_width && (width + info->advance > max_width)) break;

        add_letter_quad(font, info, xs, ys, iw);

		xs += info->advance;
        width += info->advance;
    }

    glEnd();
}

void App_Shell::draw_texture_quad(int texture_handle, float x, float y, 
								  float width, float height) {

    bitmap_mode_begin(texture_handle);
    glBegin(GL_QUADS);

    glTexCoord2f(0, 0);
    glVertex2f(x, y);

    glTexCoord2f(1, 0);
    glVertex2f(x + width, y);

    glTexCoord2f(1, 1);
    glVertex2f(x + width, y + height);

    glTexCoord2f(0, 1);
    glVertex2f(x, y + height);

    glEnd();
    bitmap_mode_end();
}

GLuint gl_texture_from_bitmap(char *bits, int width, int height) {
    RECT rect;
    rect.left = 0;
    rect.top = 0;
    rect.right = width;
    rect.bottom = height;
    
    GLuint texture_id;
    glGenTextures(1, &texture_id);

    glBindTexture(GL_TEXTURE_2D, texture_id);

    gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_BGRA_EXT,
                      GL_UNSIGNED_BYTE, (void *)bits);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
                    GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

    return texture_id;
}

unsigned char *do_dumb_alpha_thing(unsigned char *src, int width, int height) {
    int npixels = width * height;
    unsigned char *dest = (unsigned char *)malloc(npixels * 4);

    int i;
    for (i = 0; i < npixels; i++) {
        int r = src[i * 3 + 0];
        int g = src[i * 3 + 1];
        int b = src[i * 3 + 2];

//        int a = (r + g + b) / 3;
        int a = 255;

        dest[i * 4 + 0] = b;
        dest[i * 4 + 1] = g;
        dest[i * 4 + 2] = r;
        dest[i * 4 + 3] = a;
    }

    free(src);
    return dest;
}

unsigned char *do_dumb_alpha_thing_for_font(unsigned char *src, int width, int height) {
    int npixels = width * height;
    unsigned char *dest = (unsigned char *)malloc(npixels * 4);

    int i;
    for (i = 0; i < npixels; i++) {
        int r = src[i * 3 + 0];
        int g = src[i * 3 + 1];
        int b = src[i * 3 + 2];

        int a = r;
        r = 255;
        g = 255;
        b = 255;

        dest[i * 4 + 0] = r;
        dest[i * 4 + 1] = g;
        dest[i * 4 + 2] = b;
        dest[i * 4 + 3] = a;
    }

    free(src);
    return dest;
}

bool texture_from_file(char *filename, GLuint *result,
                       int *width_result, int *height_result, bool for_font) {
    unsigned char *bitmap;
    int width, height;
    bool success = load_jpeg_file(filename, &bitmap, &width, &height);
    if (success == false) return false;

    if (for_font) {
        bitmap = do_dumb_alpha_thing_for_font(bitmap, width, height);
    } else {
        bitmap = do_dumb_alpha_thing(bitmap, width, height);
    }

    GLuint texture = gl_texture_from_bitmap((char *)bitmap, width, height);

    // Give the appropriate data values back to the caller.

    *result = texture;
    *width_result = width;
    *height_result = height;

	// @Leak:
    // By the way... since we aren't remembering the pointer to 'bitmap'
    // anywhere, we can never deallocate it, so it gets leaked.  Not a big
    // deal in this demo, but for real software, you want to change that.

    return true;
}



// Wacky structures used in the font file format.

struct Glx_Glyph_Data {
    int a, b;
    int advance;
    float left, top, right, bottom;
};

struct Glx_Tex_Font_Data {
    int num_glyphs;
    int bmp_height, bmp_width;
    int character_height;
    Glx_Glyph_Data glyphs[94];
};

#ifdef NOT
Type glxGLYPHDATA
    'glyph metrics, in pixels
    A As Long 'distance to add to the current position before drawing the character glyph
    B As Long 'width of the drawn portion of the character glyph
    gAdvance As Long 'The total width of a character to use when drawing
    'tex coords of the glyph
    TexLeft As Single
    TexTop As Single
    TexRight As Single
    TexBottom As Single
End Type


Each font file begins with a header which contains the array: 
Type glxTEXFONTDATA
    Name As String
    NumGlyphs As Long
    'size in pixels
    BmpHeight As Long
    BmpWidth As Long
    BmpFontHeight As Long 'total height of a font character
    'size in tex coords
    Glyph(1 To 94) As glxGLYPHDATA
End Type
#endif NOT

char *append(char *name, char *extension) {
    int len_total = strlen(name) + strlen(extension);

    char *filename = new char[len_total + 1];
    strcpy(filename, name);
    strcat(filename, extension);

    return filename;
}

bool App_Shell::load_character_map(Font *font, char *name) {
    char *filename = append(name, ".font_map");

    FILE *f = fopen(filename, "rb");
    if (!f) return false;

    Glx_Tex_Font_Data data;

    unsigned int low = fgetc(f);
    unsigned int high = fgetc(f);

    int num_chars_to_eat = (high << 8) | low;
    int i;
    for (i = 0; i < num_chars_to_eat; i++) {
        fgetc(f);
    }

    int len = fread(&data, sizeof(data), 1, f);
    delete [] filename;
    fclose(f);

    if (len != 1) return false;

    int num_characters = 94;
    font->character_info = new Font_Character_Info[num_characters];
    font->character_range_low = 32;
    font->character_range_high = font->character_range_low + num_characters - 1;
    font->character_height = data.character_height;

    for (i = 0; i < num_characters; i++) {
        Font_Character_Info *info = &font->character_info[i];
        Glx_Glyph_Data *glyph = &data.glyphs[i];
        info->a = glyph->a;
        info->b = glyph->b;
        info->advance = glyph->advance;
        info->u0 = glyph->left;
        info->u1 = glyph->right;
        info->v0 = 1.0f - glyph->bottom;
        info->v1 = 1.0f - glyph->top;
    }

    return true;
}

Font *App_Shell::load_font(char *name) {
    Loaded_Texture_Info info;

    char *texture_name = append(name, ".jpg");
    load_texture(&info, texture_name, true);
    delete [] texture_name;
    if (!info.loaded_successfully) return NULL;

    Font *result = new Font();
    result->texture_handle = info.texture_handle;
    result->texture_width = info.width;
    result->texture_height = info.height;

    bool success = load_character_map(result, name);
    if (!success) {
        delete result;
        return NULL;
    }

    return result;
}

void App_Shell::load_texture(Loaded_Texture_Info *info, char *name, bool for_font) {
	GLuint handle;
    bool success = texture_from_file(name, &handle,
                                     &info->width, &info->height, for_font);
    if (!success) success = texture_from_file("data\\ground.jpg", &handle,
                                     &info->width, &info->height, for_font);
	info->texture_handle = handle;
    info->loaded_successfully = success;
}

int App_Shell::find_or_load_texture(char *name, char *prefix) {
    Loaded_Texture_Record *record;
    Foreach(loaded_textures, record) {
        if (strcmp(name, record->name) == 0) return record->texture_handle;
    } Endeach;

    char *suffix = ".jpg";

    int len = strlen(name) + strlen(prefix) + strlen(suffix) + 1;
    char *full_name = new char[len];
    strcpy(full_name, prefix);
    strcat(full_name, name);
    strcat(full_name, suffix);

    Loaded_Texture_Info info;
    load_texture(&info, full_name);
    delete [] full_name;

    if (!info.loaded_successfully) return 0;

    record = new Loaded_Texture_Record();
    record->name = app_strdup(name);
    record->texture_handle = info.texture_handle;
    loaded_textures->add(record);
    
    return info.texture_handle;
}

void App_Shell::init_textures() {
}


void App_Shell::line_mode_begin() {
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, screen_width, 0, screen_height, 0, -100);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glDepthFunc(GL_ALWAYS);
    glDisable(GL_LIGHTING);
    glDisable(GL_CULL_FACE);
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);

    draw_mode = MODE_LINE;
}

void App_Shell::line_mode_end() {
    draw_mode = MODE_NONE;
}

void App_Shell::triangle_mode_begin() {
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glDepthFunc(GL_LESS);
    glDisable(GL_LIGHTING);
    glDisable(GL_CULL_FACE);
    glDisable(GL_TEXTURE_2D);

    draw_mode = MODE_TRIANGLE;
}

void App_Shell::triangle_mode_end() {
    draw_mode = MODE_NONE;
}

void App_Shell::bitmap_mode_begin(int texture_handle) {
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, screen_width, 0, screen_height, 0, -100);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glDepthFunc(GL_ALWAYS);
    glDisable(GL_LIGHTING);
    glDisable(GL_CULL_FACE);

    glBindTexture(GL_TEXTURE_2D, texture_handle);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glEnable(GL_TEXTURE_2D);
    GLfloat ambient[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    draw_mode = MODE_BITMAP;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -