int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow) { // Initialize the game's settings // In the future probably read this from a file GameSettings * gameSettings = new GameSettings("They Come At Night", /* Full Screen = */ false); // Use this option to set the game to run Engine tests gameSettings->m_TestMode = true; g_Engine = new Engine(); bool result = g_Engine->Initialize(gameSettings); CHECKFAIL(result, "Failed to initialize the game engine.\n") result = g_Engine->Run(); CHECKFAIL(result, "Engine stopped running unexpectedly.\n") result = g_Engine->Shutdown(); CHECKFAIL(result, "Engine shutdown failed.\n") delete g_Engine; return 0; }
int init_scanline(TTF_Scan_Line *scanline, int base_size) { CHECKPTR(scanline); RETINIT(SUCCESS); scanline->x = malloc(base_size * sizeof(*scanline->x)); CHECKFAIL(scanline->x, warnerr("failed to alloc scanline")); scanline->size_x = base_size; scanline->num_intersections = 0; RETFAIL(free_scanline(scanline)); }
static int add_intersection(TTF_Scan_Line *scanline, float x) { CHECKPTR(scanline); RETINIT(SUCCESS); if (scanline->num_intersections+1 > scanline->size_x) { /* Increase size of scan-line storage for new intersection. */ scanline->x = realloc(scanline->x, (scanline->size_x * 2) * sizeof(*scanline->x)); CHECKFAIL(scanline->x, warnerr("failed to adjust scanline size")); scanline->size_x *= 2; } scanline->x[scanline->num_intersections++] = x; RET; }
int save_bitmap(TTF_Bitmap *bitmap, const char *filename, const char *title) { FILE *fp = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_byte *row = NULL; RETINIT(SUCCESS); CHECKFAIL(bitmap, warn("failed to save uninitialized bitmap")); // Open file for writing (binary mode) fp = fopen(filename, "wb"); CHECKFAIL(fp, warnerr("failed to open file '%s' for saving bitmap", filename)); // Initialize the write structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); CHECKFAIL(png_ptr, warn("failed to alloc png write struct")); // Initialize the info structure info_ptr = png_create_info_struct(png_ptr); CHECKFAIL(info_ptr, warn("failed to alloc png info struct")); // Setup libpng exception handling CHECKFAIL(setjmp(png_jmpbuf(png_ptr)) == 0, warn("error occurred during png creation")); png_init_io(png_ptr, fp); // Write header (8 bit colour depth) png_set_IHDR(png_ptr, info_ptr, bitmap->w, bitmap->h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); // Set png title if (title) { png_text png_title; png_title.compression = PNG_TEXT_COMPRESSION_NONE; png_title.key = (png_charp) "Title"; png_title.text = (png_charp) title; png_set_text(png_ptr, info_ptr, &png_title, 1); } png_write_info(png_ptr, info_ptr); // Allocate memory for one row (RBG = 3 bytes / pixel) row = (png_byte *) malloc((bitmap->w * 3) * sizeof(*row)); CHECKFAIL(row, warnerr("failed to alloc png row")); // Write image data int x, y; for (y = 0; y < bitmap->h; y++) { for (x = 0; x < bitmap->w; x++) { set_rgb(&(row[x*3]), bitmap->data[y*bitmap->w + x]); } png_write_row(png_ptr, (png_bytep)row); } // End write png_write_end(png_ptr, NULL); RETRELEASE( /* RELEASE */ if (row) free(row); if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); if (png_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); if (fp) fclose(fp); );
int scan_glyph(TTF_Font *font, TTF_Glyph *glyph) { CHECKPTR(font); CHECKPTR(glyph); RETINIT(SUCCESS); if (!glyph->outline) { warn("failed to scan uninitialized glyph outline"); return FAILURE; } else if (glyph->outline->point < 0) { warn("failed to scan unscaled glyph outline"); return FAILURE; } else if (glyph->number_of_contours == 0) { /* Zero-length glyph with no outline. */ return SUCCESS; } TTF_Outline *outline = glyph->outline; TTF_Bitmap *bitmap = NULL; uint32_t bg, fg; if (font->raster_flags & RENDER_FPAA) { /* Anti-aliased rendering - oversample outline then downsample. */ bg = 0xFFFFFF; fg = 0x000000; if (!glyph->bitmap) { glyph->bitmap = create_bitmap((outline->x_max - outline->x_min) / 2, (outline->y_max - outline->y_min) / 2, bg); } /* Intermediate oversampled bitmap. */ bitmap = create_bitmap(outline->x_max - outline->x_min, outline->y_max - outline->y_min, bg); } else if (font->raster_flags & RENDER_ASPAA) { /* Sub-pixel rendering - oversample in x-direction then downsample. */ bg = 0xFFFFFF; fg = 0x000000; if (!glyph->bitmap) { glyph->bitmap = create_bitmap((outline->x_max - outline->x_min) / 3, outline->y_max - outline->y_min, bg); } /* Intermediate oversampled bitmap. */ bitmap = create_bitmap(outline->x_max - outline->x_min, outline->y_max - outline->y_min, bg); } else { /* Normal rendering - write directly to glyph bitmap. */ bg = 0xFFFFFF; fg = 0x000000; if (!glyph->bitmap) { glyph->bitmap = create_bitmap(outline->x_max - outline->x_min, outline->y_max - outline->y_min, bg); } bitmap = glyph->bitmap; } /* Create a scan-line for each row in the scaled outline. */ int num_scanlines = outline->y_max - outline->y_min; TTF_Scan_Line *scanlines = malloc(num_scanlines * sizeof(*scanlines)); CHECKFAIL(scanlines, warnerr("failed to alloc glyph scan lines")); /* Find intersections of each scan-line with contour segments. */ for (int i = 0; i < num_scanlines; i++) { TTF_Scan_Line *scanline = &scanlines[i]; init_scanline(scanline, outline->num_contours * 2); scanline->y = outline->y_max - i; for (int j = 0; j < outline->num_contours; j++) { TTF_Contour *contour = &outline->contours[j]; int k; for (k = 0; k < contour->num_segments; k++) { TTF_Segment *segment = &contour->segments[k]; intersect_segment(segment, scanline); } } /* Round pixel intersection values to 1/64 of a pixel. */ for (int j = 0; j < scanline->num_intersections; j++) { scanline->x[j] = round_pixel(scanline->x[j]); } /* Sort intersections from left to right. */ qsort(scanline->x, scanline->num_intersections, sizeof(*scanline->x), cmp_intersections); // printf("Intersections: "); // char *sep = ""; // for (int j = 0; j < scanline->num_intersections; j++) { // printf("%s%f", sep, scanline->x[j]); // sep = ", "; // } // printf("\n"); int int_index = 0, fill = 0; for (int j = 0; j < bitmap->w; j++) { if (int_index < scanline->num_intersections) { if ((outline->x_min + j) >= scanline->x[int_index]) { fill = !fill; /* Skip over duplicate intersections. */ int k; for (k = 1; int_index+k < scanline->num_intersections; k++) { if (scanline->x[int_index] != scanline->x[int_index+k]) { break; } } int_index += k; } } if (fill) { bitmap_set(bitmap, j, i, fg); } } } if (font->raster_flags & RENDER_FPAA) { /* Downsample intermediate bitmap. */ for (int y = 0; y < glyph->bitmap->h; y++) { for (int x = 0; x < glyph->bitmap->w; x++) { /* Calculate pixel coverage: * coverage = number filled samples / number samples */ float coverage = 0; if (bitmap_get(bitmap, (2*x), (2*y)) == 0x000000) coverage++; if (bitmap_get(bitmap, (2*x)+1, (2*y)) == 0x000000) coverage++; if (bitmap_get(bitmap, (2*x), (2*y)+1) == 0x000000) coverage++; if (bitmap_get(bitmap, (2*x)+1, (2*y)+1) == 0x000000) coverage++; coverage /= 4; uint8_t shade = 0xFF*(1-coverage); uint32_t pixel = (shade << 16) | (shade << 8) | (shade << 0); bitmap_set(glyph->bitmap, x, y, pixel); } } free_bitmap(bitmap); } else if (font->raster_flags & RENDER_ASPAA) { /* Perform five element low-pass filter. */ TTF_Bitmap *temp = create_bitmap(bitmap->w, bitmap->h, bg); for (int y = 0; y < bitmap->h; y++) { for (int x = 0; x < bitmap->w; x++) { uint32_t pixel = 0x000000; pixel += bitmap_get(bitmap, x-2, y) * (1.0 / 9.0); pixel += bitmap_get(bitmap, x-1, y) * (2.0 / 9.0); pixel += bitmap_get(bitmap, x, y) * (3.0 / 9.0); pixel += bitmap_get(bitmap, x+1, y) * (2.0 / 9.0); pixel += bitmap_get(bitmap, x+2, y) * (1.0 / 9.0); bitmap_set(temp, x, y, pixel); } } free_bitmap(bitmap); bitmap = temp; /* Downsample intermediate bitmap. */ for (int y = 0; y < glyph->bitmap->h; y++) { for (int x = 0; x < glyph->bitmap->w; x++) { uint8_t r, g, b; r = (bitmap_get(bitmap, (3*x), y) * 0xFF) / 0xFFFFFF; g = (bitmap_get(bitmap, (3*x)+1, y) * 0xFF) / 0xFFFFFF; b = (bitmap_get(bitmap, (3*x)+2, y) * 0xFF) / 0xFFFFFF; uint32_t pixel = (r << 16) | (g << 8) | (b << 0); bitmap_set(glyph->bitmap, x, y, pixel); } } free_bitmap(bitmap); } RETRELEASE(free_scanlines(scanlines, num_scanlines)); }