Skip to content

Instantly share code, notes, and snippets.

@pastagatsan
Created June 30, 2018 13:10
Show Gist options
  • Save pastagatsan/04ad9bcb8a8bf19303dd7f79e70d5cba to your computer and use it in GitHub Desktop.
Save pastagatsan/04ad9bcb8a8bf19303dd7f79e70d5cba to your computer and use it in GitHub Desktop.
OrzoEngine - loading TGA images and displaying them in xterm256-color
#include "orzosimplesurface.h"
#include "targa.h"
#include <stdlib.h>
#include <math.h>
void SetupColorPairs()
{
int i;
for (i = 1; i <= 256; i++) {
init_pair(i, 0, i-1);
}
}
uint8_t RGB256ToCol(uint8_t r, uint8_t g, uint8_t b, uint8_t gr)
{
if (abs(r - g) <= gr && abs(g - b) <= gr && abs(b - r) <= gr) {
int mean = (r + g + b) / 3;
int ncol = round((mean / 10.625));
if (!ncol) { return 0; }
return 231 + ncol;
}
return RGB6ToCol(round((r / 42.5) - 1), round((g / 42.5) - 1),
round((b / 42.5) - 1));
}
uint8_t RGB6ToCol(int r, int g, int b)
{
if (r > 5) r = 5;
if (r < 0) r = 0;
if (g > 5) g = 5;
if (g < 0) g = 0;
if (b > 5) b = 5;
if (b < 0) b = 0;
return 16 + 36 * r + 6 * g + b;
}
OrzoSimpleSurface* OSS_New(size_t width, size_t height)
{
OrzoSimpleSurface* oss = malloc(sizeof(OrzoSimpleSurface));
oss->width = width;
oss->height = height;
oss->pixels = malloc(width * sizeof(uint8_t*));
int x;
for (x = 0; x < width; x++) {
oss->pixels[x] = malloc(height * sizeof(uint8_t));
}
OSS_Clear(oss, 0);
return oss;
}
OrzoSimpleSurface* OSS_NewFromTGA(char* filename)
{
Targa* tga = Targa_New();
Targa_Read(tga, filename);
OrzoSimpleSurface* oss = OSS_New(tga->width, tga->height);
int x, y;
for (x = 0; x < tga->width; x++) {
for (y = 0; y < tga->height; y++) {
uint32_t tgapix = tga->pixels[x][y];
uint8_t r = (tgapix & 0xFF00) >> 8, g = tgapix & 0xFF,
b = (tgapix & 0xFF000000) >> 24;
oss->pixels[x][y] = RGB256ToCol(r, g, b, 5);
}
}
Targa_Delete(tga);
return oss;
}
void OSS_Clear(OrzoSimpleSurface* oss, uint8_t color)
{
int x, y;
for (x = 0; x < oss->width; x++) {
for (y = 0; y < oss->height; y++) {
oss->pixels[x][y] = color;
}
}
}
void OSS_DrawTo(OrzoSimpleSurface* s, WINDOW* w, int xpos, int ypos)
{
int x, y, xmax, ymax;
getmaxyx(w, ymax, xmax);
for (x = 0; x < s->width; x++) {
if (x > xmax) { break; }
if (x < 0) { continue; }
for (y = 0; y < s->height; y++) {
if (y > ymax) { break; }
if (y < 0) { continue; }
attron(COLOR_PAIR(s->pixels[x][y] + 1));
mvwaddch(w, y + ypos, x + xpos, ' ');
attroff(COLOR_PAIR(s->pixels[x][y] + 1));
}
}
}
void OSS_SetPixel(OrzoSimpleSurface* s, int x, int y, uint8_t col)
{
if (x < 0 || x > s->width - 1 || y < 0 || y > s->height - 1) return;
s->pixels[x][y] = col;
}
void OSS_DrawRect(OrzoSimpleSurface* s, int x, int y, int w, int h, uint8_t col)
{
int i, j;
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
OSS_SetPixel(s, x + i, y + j, col);
}
}
}
void OSS_Delete(OrzoSimpleSurface* s)
{
int x;
for (x = 0; x < s->width; x++) {
free(s->pixels[x]);
}
free(s->pixels);
free(s);
}
#pragma once
#include <ncurses.h>
#include <stdint.h>
typedef struct {
size_t width, height;
uint8_t** pixels;
} OrzoSimpleSurface;
/* Initialises color pairs 1 - 256 for OrzoSimpleSurface
*
* Any one of these color pairs 'x' corresponds to a background of color x-1
* and a foreground color of 0 (COLOR_BLACK)
*/
void SetupColorPairs();
/*
* Converts a 24-bit RGB colour to an xterm-256 colour.
*
* If the components r, g and b differ between eachother by greyscalerange
* or less, the colour is considered greyscale and colours 0, 232-255 are used.
* Otherwise, colours 16-231 are used.
*/
uint8_t RGB256ToCol(uint8_t r, uint8_t g, uint8_t b, uint8_t greyscalerange);
uint8_t RGB6ToCol(int r, int g, int b);
/* Creates a new OrzoSimpleSurface */
OrzoSimpleSurface* OSS_New(size_t width, size_t height);
/* Creates a new OrzoSimpleSurface from an uncompressed TGA. Pixels colours are
* approximated using RGB256ToCol.
*
* Only unmapped RGB (data type 2) targa files are accepted.
*/
OrzoSimpleSurface* OSS_NewFromTGA(char* filename);
/* Sets each pixel in the surface to color */
void OSS_Clear(OrzoSimpleSurface* oss, uint8_t color);
/* Draws an OrzoSimpleSurface's pixel information to a window at an xpos and
* ypos.
*/
void OSS_DrawTo(OrzoSimpleSurface* s, WINDOW* w, int xpos, int ypos);
void OSS_SetPixel(OrzoSimpleSurface* s, int x, int y, uint8_t col);
void OSS_DrawRect(OrzoSimpleSurface* s, int x, int y, int w, int h, uint8_t c);
/* Delete an OrzoSimpleSurface instance */
void OSS_Delete(OrzoSimpleSurface* s);
#include "targa.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
Targa* Targa_New()
{
Targa* t = malloc(sizeof(Targa));
memset(t, 0, sizeof(Targa));
return t;
}
void Targa_AllocatePixelMemory(Targa* t)
{
t->pixels = malloc(t->width * sizeof(uint32_t*));
int x;
for (x = 0; x < t->width; x++) {
t->pixels[x] = malloc(t->height * sizeof(uint32_t));
}
}
void Targa_Read(Targa* t, char* filename)
{
FILE* file = fopen(filename, "r");
fread(&t->idlength, 1, 1, file);
fread(&t->colourmaptype, 1, 1, file);
fread(&t->datatypecode, 1, 1, file);
fread(&t->colourmaporigin, 2, 1, file);
fread(&t->colourmaplength, 2, 1, file);
fread(&t->colourmapdepth, 1, 1, file);
fread(&t->x_origin, 2, 1, file);
fread(&t->y_origin, 2, 1, file);
fread(&t->width, 2, 1, file);
fread(&t->height, 2, 1, file);
fread(&t->bitsperpixel, 1, 1, file);
fread(&t->imagedescriptor, 2, 1, file);
Targa_PrintHeader(t);
if (t->bitsperpixel != 32 && t->bitsperpixel != 24) {
printf("Targa file %s has %d bits per pixel. Only 24/32 are "
"accepted.\n", filename, t->bitsperpixel);
fclose(file);
return;
}
if (t->datatypecode != 2) { // i.e. if it is not uncompressed RGB
printf("Targa file %s is not uncompressed RGB.\n", filename);
fclose(file);
return;
}
uint32_t pixel;
char pixel_length = t->bitsperpixel / 8;
size_t area = t->width * t->height;
size_t amount_to_read = pixel_length * area;
Targa_AllocatePixelMemory(t);
int k;
for (k = 0; k < area; k++) {
pixel = 0;
fread(&pixel, pixel_length, 1, file);
if (t->bitsperpixel == 32) {
pixel = (pixel & 0x00FFFFFF);
}
int x = k % t->width;
int y = floor((t->height) - (k / t->width));
t->pixels[x][y] = pixel;
}
if (!feof(file)) {
printf("Some error reading Targa file %s occurred.\n", filename);
fclose(file);
return;
}
fclose(file);
}
void Targa_PrintHeader(Targa* t)
{
printf("sizeof header = %lu\n", sizeof(Targa) - sizeof(uint32_t**));
printf("ID Length: %d\n", t->idlength);
printf("Colour map type: %d\n", t->colourmaptype);
printf("Data Type Code: %d\n", t->datatypecode);
printf("Colour Map Origin: %d\n", t->colourmaporigin);
printf("Colour Map Length: %d\n", t->colourmaplength);
printf("Colour Map Depth: %d\n", t->colourmapdepth);
printf("X Origin: %d\n", t->x_origin);
printf("Y Origin: %d\n", t->y_origin);
printf("Width: %d\n", t->width);
printf("Height: %d\n", t->height);
printf("Bits per pixel: %d\n", t->bitsperpixel);
printf("Image descriptor: %d\n", t->imagedescriptor);
}
void Targa_Delete(Targa* t)
{
int x;
for (x = 0; x < t->width; x++) {
if (t->pixels[x]) free(t->pixels[x]);
}
if (t->pixels) free(t->pixels);
free(t);
}
#pragma once
#include <stdint.h>
typedef struct {
int8_t idlength;
int8_t colourmaptype;
int8_t datatypecode;
int16_t colourmaporigin;
int16_t colourmaplength;
int8_t colourmapdepth;
int16_t x_origin;
int16_t y_origin;
int16_t width;
int16_t height;
int8_t bitsperpixel;
int8_t imagedescriptor;
uint32_t** pixels;
} Targa;
Targa* Targa_New();
void Targa_AllocatePixelMemory(Targa* t);
void Targa_Read(Targa* dest, char* filename);
void Targa_PrintHeader(Targa* t);
void Targa_Delete(Targa* t);
#include <stdio.h>
#include <ncurses.h>
#include "orzosimplesurface.h"
#include "targa.h"
int main()
{
OrzoSimpleSurface* s = OSS_NewFromTGA("dike2.tga");
getch();
initscr();
start_color();
SetupColorPairs();
int c, x, y;
do {
if (c == 'w') {
y--;
} else if (c == 's') {
y++;
} else if (c == 'a') {
x--;
} else if (c == 'd') {
x++;
}
OSS_DrawTo(s, stdscr, 0, 0);
} while ((c = getch()) != 'q');
endwin();
OSS_Delete(s);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment