X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_tex.h;h=f570b11684fe367af76f8819dec2501050b5e307;hp=3f9cd9850eb8ae45191d0dd5ddb24250e58d2bb9;hb=HEAD;hpb=fac9f6fff674421f27fa4f4c1d2844998f0003d6 diff --git a/vg_tex.h b/vg_tex.h index 3f9cd98..24a99a0 100644 --- a/vg_tex.h +++ b/vg_tex.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved +/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved * * A portion of this file is copied and altered from the QOI projects' source, * Originally written by Dominic Szablewski. It is slightly modified. @@ -30,27 +30,10 @@ SOFTWARE. */ -#ifndef VG_TEX_H -#define VG_TEX_H - -#define VG_GAME -#include "vg/vg.h" -#include "vg/vg_log.h" - -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include "vg/submodules/stb/stb_image_write.h" - -/* its a sad day. */ -#if 0 -#define STBI_MALLOC(X) -#define STBI_REALLOC(X,Y) -#define STBI_FREE(X) -#endif - -#define STBI_ONLY_JPEG -#define STBI_NO_THREAD_LOCALS -#define STB_IMAGE_IMPLEMENTATION -#include "vg/submodules/stb/stb_image.h" +#pragma once +#include "vg_log.h" +#include "vg_image.h" +#include "vg_engine.h" struct vg_sprite { @@ -63,277 +46,12 @@ struct vg_sprite #define VG_TEX2D_CLAMP 0x8 #define VG_TEX2D_NOMIP 0x10 -static u8 const_vg_tex2d_err[] ={ - 0xff,0x00,0xff,0xff, 0x00,0x00,0x00,0xff, - 0xff,0x00,0xff,0xff, 0x00,0x00,0x00,0xff, - 0x00,0x00,0x00,0xff, 0xff,0x00,0xff,0xff, - 0x00,0x00,0x00,0xff, 0xff,0x00,0xff,0xff, - 0xff,0x00,0xff,0xff, 0x00,0x00,0x00,0xff, - 0xff,0x00,0xff,0xff, 0x00,0x00,0x00,0xff, - 0x00,0x00,0x00,0xff, 0xff,0x00,0xff,0xff, - 0x00,0x00,0x00,0xff, 0xff,0x00,0xff,0xff, -}; - -#define QOI_SRGB 0 -#define QOI_LINEAR 1 - -typedef struct { - unsigned int width; - unsigned int height; - unsigned char channels; - unsigned char colorspace; -} qoi_desc; - -#ifndef QOI_ZEROARR - #define QOI_ZEROARR(a) memset((a),0,sizeof(a)) -#endif - -#define QOI_OP_INDEX 0x00 /* 00xxxxxx */ -#define QOI_OP_DIFF 0x40 /* 01xxxxxx */ -#define QOI_OP_LUMA 0x80 /* 10xxxxxx */ -#define QOI_OP_RUN 0xc0 /* 11xxxxxx */ -#define QOI_OP_RGB 0xfe /* 11111110 */ -#define QOI_OP_RGBA 0xff /* 11111111 */ - -#define QOI_MASK_2 0xc0 /* 11000000 */ - -#define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11) -#define QOI_MAGIC \ - (((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \ - ((unsigned int)'i') << 8 | ((unsigned int)'f')) -#define QOI_HEADER_SIZE 14 - -/* 2GB is the max file size that this implementation can safely handle. We guard -against anything larger than that, assuming the worst case with 5 bytes per -pixel, rounded down to a nice clean value. 400 million pixels ought to be -enough for anybody. */ -#define QOI_PIXELS_MAX ((unsigned int)400000000) - -typedef union { - struct { unsigned char r, g, b, a; } rgba; - unsigned int v; -} qoi_rgba_t; +/* options to create texutres; call only from loader thread. + * *dest will be replaced synchronously by the main thread when ready. */ -static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1}; -static u32 qoi_read_32( const u8 *bytes, int *p ) { - u32 a = bytes[(*p)++]; - u32 b = bytes[(*p)++]; - u32 c = bytes[(*p)++]; - u32 d = bytes[(*p)++]; - return a << 24 | b << 16 | c << 8 | d; -} - -struct texture_load_info{ - GLuint *dest; - u32 width, height, flags; - u8 *rgba; -}; - -static void async_vg_tex2d_upload( void *payload, u32 size ) -{ - if( vg_thread_purpose() != k_thread_purpose_main ){ - vg_fatal_error( "Catastrophic programming error.\n" ); - } - - struct texture_load_info *info = payload; - - glGenTextures( 1, info->dest ); - glBindTexture( GL_TEXTURE_2D, *info->dest ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, info->width, info->height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, info->rgba ); - - if( !(info->flags & VG_TEX2D_NOMIP) ){ - glGenerateMipmap( GL_TEXTURE_2D ); - } - - if( info->flags & VG_TEX2D_LINEAR ){ - if( info->flags & VG_TEX2D_NOMIP ){ - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - } - else{ - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_LINEAR_MIPMAP_LINEAR ); - } - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - - if( info->flags & VG_TEX2D_NEAREST ){ - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } - - if( info->flags & VG_TEX2D_CLAMP ){ - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } - - if( info->flags & VG_TEX2D_REPEAT ){ - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - } -} - -static void vg_tex2d_replace_with_error( GLuint *dest ) -{ - u32 hdr_size = vg_align8(sizeof(struct texture_load_info)); +void vg_tex2d_replace_with_error_async( GLuint *dest ); - vg_async_item *call = vg_async_alloc( hdr_size ); - struct texture_load_info *info = call->payload; - - info->dest = dest; - info->flags = VG_TEX2D_NEAREST|VG_TEX2D_REPEAT|VG_TEX2D_NOMIP; - info->width = 4; - info->height = 4; - info->rgba = const_vg_tex2d_err; - - vg_async_dispatch( call, async_vg_tex2d_upload ); -} - -static void vg_tex2d_load_qoi_async( const u8 *bytes, u32 size, - u32 flags, GLuint *dest ) -{ - u32 header_magic; - qoi_rgba_t index[64]; - qoi_rgba_t px; - int px_len, chunks_len, px_pos; - int p = 0, run = 0; - - u32 channels = 4; /* TODO */ - - qoi_desc desc; - - if ( - bytes == NULL || - (channels != 0 && channels != 3 && channels != 4) || - size < QOI_HEADER_SIZE + (int)sizeof(qoi_padding) - ) { - vg_error( "Error while decoding qoi file: illegal parameters\n" ); - vg_tex2d_replace_with_error( dest ); - return; - } - - header_magic = qoi_read_32(bytes, &p); - desc.width = qoi_read_32(bytes, &p); - desc.height = qoi_read_32(bytes, &p); - desc.channels = bytes[p++]; - desc.colorspace = bytes[p++]; - - if ( - desc.width == 0 || desc.height == 0 || - desc.channels < 3 || desc.channels > 4 || - desc.colorspace > 1 || - header_magic != QOI_MAGIC || - desc.height >= QOI_PIXELS_MAX / desc.width - ) { - vg_error( "Error while decoding qoi file: invalid file\n" ); - vg_tex2d_replace_with_error( dest ); - return; - } - - if (channels == 0) { - channels = desc.channels; - } - - px_len = desc.width * desc.height * channels; - - /* allocate async call - * -------------------------- - */ - u32 hdr_size = vg_align8(sizeof(struct texture_load_info)), - tex_size = vg_align8(px_len); - - vg_async_item *call = vg_async_alloc( hdr_size + tex_size ); - struct texture_load_info *info = call->payload; - - info->dest = dest; - info->flags = flags; - info->width = desc.width; - info->height = desc.height; - info->rgba = ((u8*)call->payload) + hdr_size; - - /* - * Decode - * ---------------------------- - */ - - u8 *pixels = info->rgba; - - QOI_ZEROARR(index); - px.rgba.r = 0; - px.rgba.g = 0; - px.rgba.b = 0; - px.rgba.a = 255; - - chunks_len = size - (int)sizeof(qoi_padding); - for (px_pos = 0; px_pos < px_len; px_pos += channels) { - if (run > 0) { - run--; - } - else if (p < chunks_len) { - int b1 = bytes[p++]; - - if (b1 == QOI_OP_RGB) { - px.rgba.r = bytes[p++]; - px.rgba.g = bytes[p++]; - px.rgba.b = bytes[p++]; - } - else if (b1 == QOI_OP_RGBA) { - px.rgba.r = bytes[p++]; - px.rgba.g = bytes[p++]; - px.rgba.b = bytes[p++]; - px.rgba.a = bytes[p++]; - } - else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) { - px = index[b1]; - } - else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) { - px.rgba.r += ((b1 >> 4) & 0x03) - 2; - px.rgba.g += ((b1 >> 2) & 0x03) - 2; - px.rgba.b += ( b1 & 0x03) - 2; - } - else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) { - int b2 = bytes[p++]; - int vg = (b1 & 0x3f) - 32; - px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f); - px.rgba.g += vg; - px.rgba.b += vg - 8 + (b2 & 0x0f); - } - else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) { - run = (b1 & 0x3f); - } - - index[QOI_COLOR_HASH(px) % 64] = px; - } - - pixels[px_pos + 0] = px.rgba.r; - pixels[px_pos + 1] = px.rgba.g; - pixels[px_pos + 2] = px.rgba.b; - - if (channels == 4) { - pixels[px_pos + 3] = px.rgba.a; - } - } - - /* - * Complete the call - * -------------------------- - */ - - vg_async_dispatch( call, async_vg_tex2d_upload ); -} - -static -void vg_tex2d_load_qoi_async_file( const char *path, u32 flags, GLuint *dest ) -{ - if( vg_thread_purpose() != k_thread_purpose_loader ) - vg_fatal_error( "wrong thread\n" ); - - vg_linear_clear( vg_mem.scratch ); - - u32 size; - const void *data = vg_file_read( vg_mem.scratch, path, &size ); - vg_tex2d_load_qoi_async( data, size, flags, dest ); -} + u32 flags, GLuint *dest ); -#endif /* VG_TEX_H */ +void vg_tex2d_load_qoi_async_file( const char *path, u32 flags, GLuint *dest );