From 4bf61f911194bb0b40d302df8d7dfff2fda19892 Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Wed, 30 Mar 2016 08:25:04 +0200 Subject: Initial commit. --- src/renderer.c | 473 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 src/renderer.c (limited to 'src/renderer.c') diff --git a/src/renderer.c b/src/renderer.c new file mode 100644 index 0000000..11c3706 --- /dev/null +++ b/src/renderer.c @@ -0,0 +1,473 @@ +#define _RENDERER_C +#include "common.h" +#include + +#define FONT_FILE "assets/font.png" + +float r_color_white[4] = {1, 1, 1, 1}; +float r_color_black[4] = {0, 0, 0, 1}; +float r_color_red[4] = {1, 0, 0, 1}; +float r_color_blue[4] = {0, 0, 1, 1}; + +static struct { + SDL_Surface *font; + float font_aspect_ratio; + + r_window *windows; +} rs; + +int r_init(void) +{ + memset(&rs, 0, sizeof(rs)); + + con_printf("r_init: initializing SDL...\n"); + if (SDL_Init(SDL_INIT_VIDEO) == -1) { + con_printf("r_init: SDL_Init(SDL_INIT_VIDEO) failed: %s\n", + SDL_GetError()); + goto error; + } + + con_printf("r_init: initializing SDL_image...\n"); + if (IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG) != + (IMG_INIT_JPG | IMG_INIT_PNG)) { + con_printf("r_init: IMG_Init failed: %s\n", SDL_GetError()); + goto error; + } + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); + + con_printf("r_init: loading font \""FONT_FILE"\"...\n"); + rs.font = IMG_Load("assets/font.png"); + if (!rs.font) { + con_printf("r_init: IMG_Load failed: %s\n", + IMG_GetError()); + goto error; + } + + rs.font_aspect_ratio = (float)rs.font->w / rs.font->h; + + con_printf("r_init: renderer init complete\n"); + return 0; + +error: + r_quit(); + return 1; +} + +r_window *r_window_create(void) +{ + r_window *rw; + + rw = calloc(1, sizeof(r_window)); + if (!rw) + abort(); + + rw->prev = NULL; + if (rs.windows) + rs.windows->prev = rw; + rw->next = rs.windows; + rs.windows = rw; + + rw->window = SDL_CreateWindow(PROGRAM_NAME, SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, 300, 300, + SDL_WINDOW_RESIZABLE); + if (!rw->window) { + con_printf("r_window_create: SDL_CreateWindow failed: %s\n", + SDL_GetError()); + goto error; + } + + rw->renderer = SDL_CreateRenderer(rw->window, -1, + SDL_RENDERER_ACCELERATED | + SDL_RENDERER_PRESENTVSYNC); + if (!rw->renderer) { + con_printf("r_window_create: SDL_CreateRenderer failed: %s\n", + SDL_GetError()); + goto error; + } + + SDL_SetRenderDrawBlendMode(rw->renderer, SDL_BLENDMODE_BLEND); + + rw->font_texture = SDL_CreateTextureFromSurface(rw->renderer, rs.font); + if (!rw->font_texture) { + con_printf("r_window_create: SDL_CreateTextureFromSurface" + " failed: %s\n", SDL_GetError()); + goto error; + } + + con_printf("r_window_create: created window #%i\n", + SDL_GetWindowID(rw->window)); + + return rw; + +error: + r_window_destroy(rw); + return NULL; +} + +void r_window_destroy(r_window *rw) +{ + SDL_DestroyTexture(rw->font_texture); + SDL_DestroyRenderer(rw->renderer); + SDL_DestroyWindow(rw->window); + + if (rw->prev) + rw->prev->next = rw->next; + if (rw->next) + rw->next->prev = rw->prev; + + if (rs.windows == rw) + rs.windows = rw->next; + + free(rw); +} + + +void r_quit(void) +{ + con_printf("r_quit: renderer is quitting\n"); + + while (rs.windows) + r_window_destroy(rs.windows); + + SDL_FreeSurface(rs.font); + IMG_Quit(); +} + +static void r_set_color(SDL_Renderer *renderer, float *color) +{ + SDL_SetRenderDrawColor(renderer, color[0] * 255, color[1] * 255, + color[2] * 255, color[3] * 255); +} + + +void r_clear(r_window *rw, float *color) +{ + r_set_color(rw->renderer, color); + SDL_RenderClear(rw->renderer); +} + +void r_flip(r_window *rw) +{ + SDL_RenderPresent(rw->renderer); +} + +void r_clip_enable(r_window *rw, float x, float y, float w, float h) +{ + SDL_Rect rect = {x, y, w, h}; + SDL_RenderSetClipRect(rw->renderer, &rect); +} + +void r_clip_disable(r_window *rw) +{ + SDL_RenderSetClipRect(rw->renderer, NULL); +} + +void r_draw_line(r_window *rw, float x0, float y0, float x1, float y1, + float *color) +{ + + r_set_color(rw->renderer, color); + SDL_RenderDrawLine(rw->renderer, x0, y0, x1, y1); +} + +void r_draw_rect(r_window *rw, float x, float y, float w, float h, float *color) +{ + SDL_Rect rect = {x, y, w, h}; + r_set_color(rw->renderer, color); + SDL_RenderFillRect(rw->renderer, &rect); +} + +static int r_iterate_chars(char **p) +{ + int rv; + + if ((*p)[0] == '\0') { + return -1; + } else if (((*p)[0] & 0b10000000) == 0b00000000) { + rv = (*p)[0]; + (*p)++; + return rv; + } else if (((*p)[0] & 0b11100000) == 0b11000000) { + if ((*p)[1] == '\0') + return -1; + + rv = (((*p)[0] & 0b00011111) << 6) | ((*p)[1] & 0b00111111); + (*p) += 2; + return rv; + } else { + (*p)++; + return 0; + } +} + +static int r_font_find_glyph(int ch) +{ + if (ch < 128) + return ch; + + switch (ch) { + case 0x105: return 128; // ą + case 0xE4: return 129; // ä + case 0x107: return 130; // ć + case 0x119: return 131; // ę + case 0xEB: return 132; // ë + case 0x142: return 133; // ł + case 0x144: return 134; // ń + case 0xF3: return 135; // ó + case 0xF6: return 136; // ö + case 0x15B: return 137; // ś + case 0xFC: return 138; // ü + case 0x17C: return 139; // ż + case 0x17A: return 140; // ź + //case 0x: return 141; // free + //case 0x: return 142; // free + //case 0x: return 143; // free + case 0x104: return 144; // Ą + case 0xC4: return 145; // Ä + case 0x106: return 146; // Ć + case 0x118: return 147; // Ę + case 0xCB: return 148; // Ë + case 0x141: return 149; // Ł + case 0x143: return 150; // Ń + case 0xD3: return 151; // Ó + case 0xD6: return 152; // Ö + case 0x15A: return 153; // Ś + case 0xDC: return 154; // Ü + case 0x17B: return 155; // Ż + case 0x179: return 156; // Ź + //case 0x: return 157; // free + //case 0x: return 158; // free + //case 0x: return 159; // free + } + + // lowercase greek + if (ch >= 0x3B1 && ch <= 0x3C1) + return ch - 0x3B1 + 160; + else if (ch >= 0x3C3 && ch <= 0x3C9) + return ch - 0x3C3 + 177; + + // uppercase greek + if (ch >= 0x391 && ch <= 0x3A1) + return ch - 0x391 + 192; + else if (ch >= 0x3A3 && ch <= 0x3A9) + return ch - 0x3A3 + 209; + + return 0; +} + +float r_text_width(float h, char *text) +{ + char *p = text; + float rv = 0; + + while(r_iterate_chars(&p) != -1) + rv += h * rs.font_aspect_ratio; + + return rv; +} + +void r_draw_text(r_window *rw, float x, float y, float h, char *text, + float *color, int flags) +{ + char *p = text; + float w = h * rs.font_aspect_ratio; + int ch; + float total_width; + + if (flags & (TEXT_CENTERX | TEXT_RIGHTX)) { + total_width = r_text_width(h, text); + + if (flags & TEXT_CENTERX) + x -= total_width / 2; + else + x -= total_width; + } + + SDL_SetTextureColorMod(rw->font_texture, color[0] * 255, color[1] * 255, + color[2] * 255); + SDL_SetTextureAlphaMod(rw->font_texture, color[3] * 255); + + while ((ch = r_iterate_chars(&p)) != -1) { + int glyph, glyph_x, glyph_y; + SDL_Rect src, dst; + + glyph = r_font_find_glyph(ch); + glyph_x = glyph % 16; + glyph_y = glyph / 16; + src.x = rs.font->w / 16 * glyph_x; + src.y = rs.font->h / 16 * glyph_y; + src.w = rs.font->w / 16; + src.h = rs.font->h / 16; + + dst.x = x; + dst.y = y; + dst.w = w; + dst.h = h; + + SDL_RenderCopy(rw->renderer, rw->font_texture, &src, &dst); + + x += w; + } +} + +static uint8_t r_float_to_u8(float num) +{ + if (num >= 1.0f) + return 255; + else if (num <= -1.0f) + return 0; + else + return floor((num + 1.0f) * 0.5f * 256.0f); +} + +static int r_xsection_alloc(SDL_Renderer *renderer, SDL_Texture **texture, + size_t width, size_t height) +{ + int old_width, old_height; + + if (*texture) { + SDL_QueryTexture(*texture, NULL, NULL, &old_width, &old_height); + + if (old_width != width || old_height != height) { + SDL_DestroyTexture(*texture); + *texture = NULL; + } + } + + if (!*texture) { + *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGR888, + SDL_TEXTUREACCESS_STREAMING, + width, height); + if (!*texture) { + con_printf("r_xsection_alloc: SDL_CreateTexture failed" + ": %s\n", SDL_GetError()); + return 1; + } + } + + return 0; +} + +void r_xsection_create(r_xsection *xsection) +{ + memset(xsection, 0, sizeof(r_xsection)); +} + +void r_xsection_destroy(r_xsection *xsection) +{ + SDL_DestroyTexture(xsection->texture); +} + +int r_xsection_update(r_window *rw, r_xsection *xsection, + phy_field_info *fi, float *field, + r_xsection_type type, float frac) +{ + size_t width, height, x, y, z; + uint8_t *pixels; + int pitch; + + switch (type) { + case XSECTION_XY: + width = fi->width; + height = fi->height; + break; + + case XSECTION_XZ: + width = fi->width; + height = fi->depth; + break; + + case XSECTION_YZ: + width = fi->height; + height = fi->depth; + break; + } + + if (frac < 0.0f) + frac = 0.0f; + else if (frac > 1.0f) + frac = 1.0f; + + if (r_xsection_alloc(rw->renderer, &xsection->texture, + width, height)) { + return 1; + } + + SDL_LockTexture(xsection->texture, NULL, (void**)&pixels, &pitch); + + switch (type) { + case XSECTION_XY: + z = frac * fi->depth; + if (z >= fi->depth) + z = fi->depth - 1; + + for (y = 0; y < fi->height; y++) + for (x = 0; x < fi->width; x++) { + uint8_t *pixel; + float *point; + + pixel = pixels + (y * pitch + x * 4); + point = field + z * fi->zstr + y * fi->ystr + + x * fi->xstr; + + pixel[0] = r_float_to_u8(point[0]); + pixel[1] = r_float_to_u8(point[1]); + pixel[2] = r_float_to_u8(point[2]); + } + break; + + case XSECTION_XZ: + y = frac * fi->height; + if (y >= fi->height) + y = fi->height - 1; + + for (z = 0; z < fi->depth; z++) + for (x = 0; x < fi->width; x++) { + uint8_t *pixel; + float *point; + + pixel = pixels + (z * pitch + x * 4); + point = field + z * fi->zstr + y * fi->ystr + + x * fi->xstr; + + pixel[0] = r_float_to_u8(point[0]); + pixel[1] = r_float_to_u8(point[1]); + pixel[2] = r_float_to_u8(point[2]); + } + break; + + case XSECTION_YZ: + x = frac * fi->width; + if (x >= fi->width) + x = fi->width - 1; + + for (z = 0; z < fi->depth; z++) + for (y = 0; y < fi->height; y++) { + uint8_t *pixel; + float *point; + + pixel = pixels + (z * pitch + y * 4); + point = field + z * fi->zstr + y * fi->ystr + + x * fi->xstr; + + pixel[0] = r_float_to_u8(point[0]); + pixel[1] = r_float_to_u8(point[1]); + pixel[2] = r_float_to_u8(point[2]); + } + break; + } + + SDL_UnlockTexture(xsection->texture); + + xsection->aspect_ratio = (float)width / height; + + return 0; +} + +void r_xsection_draw(r_window *rw, r_xsection *xsection, + float x, float y, float w, float h) +{ + SDL_Rect dst = {x, y, w, h}; + SDL_RenderCopy(rw->renderer, xsection->texture, NULL, &dst); +} -- cgit