mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-13 00:24:12 +00:00
[renderer] Move core of scrap into shared code
The actual 2d area management code is now shared, with the actual definition for scrap_t being left to the renderer specific implementation.
This commit is contained in:
parent
bfbfd7af61
commit
b6bc8ed553
7 changed files with 273 additions and 107 deletions
|
@ -31,14 +31,6 @@
|
||||||
#include "QF/qtypes.h"
|
#include "QF/qtypes.h"
|
||||||
|
|
||||||
typedef struct scrap_s scrap_t;
|
typedef struct scrap_s scrap_t;
|
||||||
typedef struct subpic_s {
|
|
||||||
const struct subpic_s * const next;
|
|
||||||
const scrap_t * const scrap;
|
|
||||||
const struct vrect_s * const rect;
|
|
||||||
const int width; ///< requested width
|
|
||||||
const int height; ///< requested height
|
|
||||||
const float size; ///< size factor for tex coords (mult)
|
|
||||||
} subpic_t;
|
|
||||||
|
|
||||||
int GLSL_LoadQuakeTexture (const char *identifier, int width, int height,
|
int GLSL_LoadQuakeTexture (const char *identifier, int width, int height,
|
||||||
byte *data);
|
byte *data);
|
||||||
|
@ -55,9 +47,11 @@ scrap_t *GLSL_CreateScrap (int size, int format, int linear);
|
||||||
void GLSL_DestroyScrap (scrap_t *scrap);
|
void GLSL_DestroyScrap (scrap_t *scrap);
|
||||||
void GLSL_ScrapClear (scrap_t *scrap);
|
void GLSL_ScrapClear (scrap_t *scrap);
|
||||||
int GLSL_ScrapTexture (scrap_t *scrap) __attribute__((pure));
|
int GLSL_ScrapTexture (scrap_t *scrap) __attribute__((pure));
|
||||||
subpic_t *GLSL_ScrapSubpic (scrap_t *scrap, int width, int height); //XXX slow!
|
//XXX slow!
|
||||||
void GLSL_SubpicDelete (subpic_t *subpic); //XXX slow!
|
struct subpic_s *GLSL_ScrapSubpic (scrap_t *scrap, int width, int height);
|
||||||
void GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch);
|
//XXX slow!
|
||||||
|
void GLSL_SubpicDelete (struct subpic_s *subpic);
|
||||||
|
void GLSL_SubpicUpdate (struct subpic_s *subpic, byte *data, int batch);
|
||||||
void GLSL_ScrapFlush (scrap_t *scrap);
|
void GLSL_ScrapFlush (scrap_t *scrap);
|
||||||
|
|
||||||
#endif//__QF_GLSL_textures_h
|
#endif//__QF_GLSL_textures_h
|
||||||
|
|
|
@ -55,6 +55,15 @@ typedef enum {
|
||||||
extern struct vid_render_funcs_s *r_funcs;
|
extern struct vid_render_funcs_s *r_funcs;
|
||||||
extern struct vid_render_data_s *r_data;
|
extern struct vid_render_data_s *r_data;
|
||||||
|
|
||||||
|
typedef struct subpic_s {
|
||||||
|
const struct subpic_s *const next;
|
||||||
|
const struct scrap_s *const scrap; ///< renderer specific type
|
||||||
|
const struct vrect_s *const rect;
|
||||||
|
const int width; ///< requested width
|
||||||
|
const int height; ///< requested height
|
||||||
|
const float size; ///< size factor for tex coords (mult)
|
||||||
|
} subpic_t;
|
||||||
|
|
||||||
// dynamic lights ===========================================================
|
// dynamic lights ===========================================================
|
||||||
|
|
||||||
typedef struct dlight_s
|
typedef struct dlight_s
|
||||||
|
|
49
include/r_scrap.h
Normal file
49
include/r_scrap.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
r_scrap.h
|
||||||
|
|
||||||
|
Renderer agnostic scrap management
|
||||||
|
|
||||||
|
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
|
||||||
|
|
||||||
|
Author: Bill Currie <bill@taniwha.org>
|
||||||
|
Date: 2021/1/12
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to:
|
||||||
|
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
59 Temple Place - Suite 330
|
||||||
|
Boston, MA 02111-1307, USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __r_scrap_h
|
||||||
|
#define __r_scrap_h
|
||||||
|
|
||||||
|
typedef struct rscrap_s {
|
||||||
|
struct vrect_s *free_rects; ///< linked list of free areas
|
||||||
|
struct vrect_s *rects; ///< linked list of allocated rects
|
||||||
|
int width; ///< overall width of scrap
|
||||||
|
int height; ///< overall height of scrap
|
||||||
|
} rscrap_t;
|
||||||
|
|
||||||
|
void R_ScrapInit (rscrap_t *scrap, int width, int height);
|
||||||
|
void R_ScrapDelete (rscrap_t *scrap);
|
||||||
|
struct vrect_s *R_ScrapAlloc (rscrap_t *scrap, int width, int height);
|
||||||
|
void R_ScrapFree (rscrap_t *scrap, struct vrect_s *rect);
|
||||||
|
void R_ScrapClear (rscrap_t *scrap);
|
||||||
|
size_t R_ScrapArea (rscrap_t *scrap) __attribute__((pure));
|
||||||
|
void R_ScrapDump (rscrap_t *scrap);
|
||||||
|
|
||||||
|
#endif//__r_scrap_h
|
|
@ -37,6 +37,7 @@ libs_video_renderer_libQFrenderer_la_DEPENDENCIES= $(renderer_libs)
|
||||||
libs_video_renderer_libQFrenderer_la_SOURCES=\
|
libs_video_renderer_libQFrenderer_la_SOURCES=\
|
||||||
libs/video/renderer/r_cvar.c \
|
libs/video/renderer/r_cvar.c \
|
||||||
libs/video/renderer/r_init.c \
|
libs/video/renderer/r_init.c \
|
||||||
|
libs/video/renderer/r_scrap.c \
|
||||||
libs/video/renderer/r_screen.c \
|
libs/video/renderer/r_screen.c \
|
||||||
libs/video/renderer/r_progs.c
|
libs/video/renderer/r_progs.c
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "QF/cmd.h"
|
#include "QF/cmd.h"
|
||||||
#include "QF/mathlib.h"
|
#include "QF/mathlib.h"
|
||||||
#include "QF/model.h"
|
#include "QF/model.h"
|
||||||
|
#include "QF/render.h"
|
||||||
#include "QF/sys.h"
|
#include "QF/sys.h"
|
||||||
#include "QF/vrect.h"
|
#include "QF/vrect.h"
|
||||||
|
|
||||||
|
@ -51,15 +52,15 @@
|
||||||
#include "QF/GLSL/funcs.h"
|
#include "QF/GLSL/funcs.h"
|
||||||
#include "QF/GLSL/qf_textures.h"
|
#include "QF/GLSL/qf_textures.h"
|
||||||
|
|
||||||
|
#include "r_scrap.h"
|
||||||
|
|
||||||
struct scrap_s {
|
struct scrap_s {
|
||||||
|
rscrap_t rscrap;
|
||||||
GLuint tnum;
|
GLuint tnum;
|
||||||
int size; // in pixels, for now, always square, power of 2
|
|
||||||
int format;
|
int format;
|
||||||
int bpp;
|
int bpp;
|
||||||
byte *data; // local copy of the texture so updates can be batched
|
byte *data; // local copy of the texture so updates can be batched
|
||||||
vrect_t *batch;
|
vrect_t *batch;
|
||||||
vrect_t *free_rects;
|
|
||||||
vrect_t *rects;
|
|
||||||
subpic_t *subpics;
|
subpic_t *subpics;
|
||||||
struct scrap_s *next;
|
struct scrap_s *next;
|
||||||
};
|
};
|
||||||
|
@ -248,23 +249,22 @@ static void
|
||||||
glsl_scraps_f (void)
|
glsl_scraps_f (void)
|
||||||
{
|
{
|
||||||
scrap_t *scrap;
|
scrap_t *scrap;
|
||||||
vrect_t *rect;
|
|
||||||
int area;
|
int area;
|
||||||
|
int size;
|
||||||
|
|
||||||
if (!scrap_list) {
|
if (!scrap_list) {
|
||||||
Sys_Printf ("No scraps\n");
|
Sys_Printf ("No scraps\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (scrap = scrap_list; scrap; scrap = scrap->next) {
|
for (scrap = scrap_list; scrap; scrap = scrap->next) {
|
||||||
for (rect = scrap->free_rects, area = 0; rect; rect = rect->next)
|
area = R_ScrapArea (&scrap->rscrap);
|
||||||
area += rect->width * rect->height;
|
// always square
|
||||||
|
size = scrap->rscrap.width;
|
||||||
Sys_Printf ("tnum=%u size=%d format=%04x bpp=%d free=%d%%\n",
|
Sys_Printf ("tnum=%u size=%d format=%04x bpp=%d free=%d%%\n",
|
||||||
scrap->tnum, scrap->size, scrap->format, scrap->bpp,
|
scrap->tnum, size, scrap->format, scrap->bpp,
|
||||||
area * 100 / (scrap->size * scrap->size));
|
area * 100 / (size * size));
|
||||||
if (Cmd_Argc () > 1) {
|
if (Cmd_Argc () > 1) {
|
||||||
for (rect = scrap->rects, area = 0; rect; rect = rect->next)
|
R_ScrapDump (&scrap->rscrap);
|
||||||
Sys_Printf ("%d %d %d %d\n", rect->x, rect->y,
|
|
||||||
rect->width, rect->height);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,11 +309,9 @@ GLSL_CreateScrap (int size, int format, int linear)
|
||||||
}
|
}
|
||||||
scrap = malloc (sizeof (scrap_t));
|
scrap = malloc (sizeof (scrap_t));
|
||||||
qfeglGenTextures (1, &scrap->tnum);
|
qfeglGenTextures (1, &scrap->tnum);
|
||||||
scrap->size = size;
|
R_ScrapInit (&scrap->rscrap, size, size);
|
||||||
scrap->format = format;
|
scrap->format = format;
|
||||||
scrap->bpp = bpp;
|
scrap->bpp = bpp;
|
||||||
scrap->free_rects = VRect_New (0, 0, size, size);
|
|
||||||
scrap->rects = 0;
|
|
||||||
scrap->subpics = 0;
|
scrap->subpics = 0;
|
||||||
scrap->next = scrap_list;
|
scrap->next = scrap_list;
|
||||||
scrap_list = scrap;
|
scrap_list = scrap;
|
||||||
|
@ -341,26 +339,13 @@ GLSL_CreateScrap (int size, int format, int linear)
|
||||||
void
|
void
|
||||||
GLSL_ScrapClear (scrap_t *scrap)
|
GLSL_ScrapClear (scrap_t *scrap)
|
||||||
{
|
{
|
||||||
vrect_t *t;
|
|
||||||
subpic_t *sp;
|
subpic_t *sp;
|
||||||
|
|
||||||
while (scrap->free_rects) {
|
|
||||||
t = scrap->free_rects;
|
|
||||||
scrap->free_rects = t->next;
|
|
||||||
VRect_Delete (t);
|
|
||||||
}
|
|
||||||
while (scrap->rects) {
|
|
||||||
t = scrap->rects;
|
|
||||||
scrap->rects = t->next;
|
|
||||||
VRect_Delete (t);
|
|
||||||
}
|
|
||||||
while (scrap->subpics) {
|
while (scrap->subpics) {
|
||||||
sp = scrap->subpics;
|
sp = scrap->subpics;
|
||||||
scrap->subpics = (subpic_t *) sp->next;
|
scrap->subpics = (subpic_t *) sp->next;
|
||||||
free (sp);
|
free (sp);
|
||||||
}
|
}
|
||||||
|
R_ScrapClear (&scrap->rscrap);
|
||||||
scrap->free_rects = VRect_New (0, 0, scrap->size, scrap->size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -375,7 +360,7 @@ GLSL_DestroyScrap (scrap_t *scrap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GLSL_ScrapClear (scrap);
|
GLSL_ScrapClear (scrap);
|
||||||
VRect_Delete (scrap->free_rects);
|
R_ScrapDelete (&scrap->rscrap);
|
||||||
GLSL_ReleaseTexture (scrap->tnum);
|
GLSL_ReleaseTexture (scrap->tnum);
|
||||||
free (scrap->data);
|
free (scrap->data);
|
||||||
free (scrap);
|
free (scrap);
|
||||||
|
@ -390,47 +375,13 @@ GLSL_ScrapTexture (scrap_t *scrap)
|
||||||
subpic_t *
|
subpic_t *
|
||||||
GLSL_ScrapSubpic (scrap_t *scrap, int width, int height)
|
GLSL_ScrapSubpic (scrap_t *scrap, int width, int height)
|
||||||
{
|
{
|
||||||
int i, w, h;
|
vrect_t *rect;
|
||||||
vrect_t **t, **best;
|
|
||||||
vrect_t *old, *frags, *rect;
|
|
||||||
subpic_t *subpic;
|
subpic_t *subpic;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
rect = R_ScrapAlloc (&scrap->rscrap, width, height);
|
||||||
if (width <= (1 << i))
|
if (!rect) {
|
||||||
break;
|
return 0;
|
||||||
w = 1 << i;
|
|
||||||
for (i = 0; i < 16; i++)
|
|
||||||
if (height <= (1 << i))
|
|
||||||
break;
|
|
||||||
h = 1 << i;
|
|
||||||
|
|
||||||
best = 0;
|
|
||||||
for (t = &scrap->free_rects; *t; t = &(*t)->next) {
|
|
||||||
if ((*t)->width < w || (*t)->height < h)
|
|
||||||
continue; // won't fit
|
|
||||||
if (!best) {
|
|
||||||
best = t;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height)
|
|
||||||
best = t;
|
|
||||||
}
|
|
||||||
if (!best)
|
|
||||||
return 0; // couldn't find a spot
|
|
||||||
old = *best;
|
|
||||||
*best = old->next;
|
|
||||||
rect = VRect_New (old->x, old->y, w, h);
|
|
||||||
frags = VRect_Difference (old, rect);
|
|
||||||
VRect_Delete (old);
|
|
||||||
if (frags) {
|
|
||||||
// old was bigger than the requested size
|
|
||||||
for (old = frags; old->next; old = old->next)
|
|
||||||
;
|
|
||||||
old->next = scrap->free_rects;
|
|
||||||
scrap->free_rects = frags;
|
|
||||||
}
|
|
||||||
rect->next = scrap->rects;
|
|
||||||
scrap->rects = rect;
|
|
||||||
|
|
||||||
subpic = malloc (sizeof (subpic_t));
|
subpic = malloc (sizeof (subpic_t));
|
||||||
*((subpic_t **) &subpic->next) = scrap->subpics;
|
*((subpic_t **) &subpic->next) = scrap->subpics;
|
||||||
|
@ -439,7 +390,7 @@ GLSL_ScrapSubpic (scrap_t *scrap, int width, int height)
|
||||||
*((vrect_t **) &subpic->rect) = rect;
|
*((vrect_t **) &subpic->rect) = rect;
|
||||||
*((int *) &subpic->width) = width;
|
*((int *) &subpic->width) = width;
|
||||||
*((int *) &subpic->height) = height;
|
*((int *) &subpic->height) = height;
|
||||||
*((float *) &subpic->size) = 1.0 / scrap->size;
|
*((float *) &subpic->size) = 1.0 / scrap->rscrap.width;
|
||||||
return subpic;
|
return subpic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,8 +399,6 @@ GLSL_SubpicDelete (subpic_t *subpic)
|
||||||
{
|
{
|
||||||
scrap_t *scrap = (scrap_t *) subpic->scrap;
|
scrap_t *scrap = (scrap_t *) subpic->scrap;
|
||||||
vrect_t *rect = (vrect_t *) subpic->rect;
|
vrect_t *rect = (vrect_t *) subpic->rect;
|
||||||
vrect_t *old, *merge;
|
|
||||||
vrect_t **t;
|
|
||||||
subpic_t **sp;
|
subpic_t **sp;
|
||||||
|
|
||||||
for (sp = &scrap->subpics; *sp; sp = (subpic_t **) &(*sp)->next)
|
for (sp = &scrap->subpics; *sp; sp = (subpic_t **) &(*sp)->next)
|
||||||
|
@ -459,29 +408,7 @@ GLSL_SubpicDelete (subpic_t *subpic)
|
||||||
Sys_Error ("GLSL_ScrapDelSubpic: broken subpic");
|
Sys_Error ("GLSL_ScrapDelSubpic: broken subpic");
|
||||||
*sp = (subpic_t *) subpic->next;
|
*sp = (subpic_t *) subpic->next;
|
||||||
free (subpic);
|
free (subpic);
|
||||||
for (t = &scrap->rects; *t; t = &(*t)->next)
|
R_ScrapFree (&scrap->rscrap, rect);
|
||||||
if (*t == rect)
|
|
||||||
break;
|
|
||||||
if (*t != rect)
|
|
||||||
Sys_Error ("GLSL_ScrapDelSubpic: broken subpic");
|
|
||||||
*t = rect->next;
|
|
||||||
|
|
||||||
do {
|
|
||||||
merge = 0;
|
|
||||||
for (t = &scrap->free_rects; *t; t = &(*t)->next) {
|
|
||||||
merge = VRect_Merge (*t, rect);
|
|
||||||
if (merge) {
|
|
||||||
old = *t;
|
|
||||||
*t = (*t)->next;
|
|
||||||
VRect_Delete (old);
|
|
||||||
VRect_Delete (rect);
|
|
||||||
rect = merge;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (merge);
|
|
||||||
rect->next = scrap->free_rects;
|
|
||||||
scrap->free_rects = rect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -502,7 +429,7 @@ GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch)
|
||||||
scrap->batch = VRect_New (rect->x, rect->y,
|
scrap->batch = VRect_New (rect->x, rect->y,
|
||||||
rect->width, rect->height);
|
rect->width, rect->height);
|
||||||
}
|
}
|
||||||
step = scrap->size * scrap->bpp;
|
step = scrap->rscrap.width * scrap->bpp;
|
||||||
sbytes = subpic->width * scrap->bpp;
|
sbytes = subpic->width * scrap->bpp;
|
||||||
dest = scrap->data + rect->y * step + rect->x * scrap->bpp;
|
dest = scrap->data + rect->y * step + rect->x * scrap->bpp;
|
||||||
for (i = 0; i < subpic->height; i++, dest += step, data += sbytes)
|
for (i = 0; i < subpic->height; i++, dest += step, data += sbytes)
|
||||||
|
@ -519,6 +446,7 @@ void
|
||||||
GLSL_ScrapFlush (scrap_t *scrap)
|
GLSL_ScrapFlush (scrap_t *scrap)
|
||||||
{
|
{
|
||||||
vrect_t *rect = scrap->batch;
|
vrect_t *rect = scrap->batch;
|
||||||
|
int size = scrap->rscrap.width;
|
||||||
|
|
||||||
if (!rect)
|
if (!rect)
|
||||||
return;
|
return;
|
||||||
|
@ -526,9 +454,9 @@ GLSL_ScrapFlush (scrap_t *scrap)
|
||||||
//should update to not update the entire horizontal block
|
//should update to not update the entire horizontal block
|
||||||
qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum);
|
qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum);
|
||||||
qfeglTexSubImage2D (GL_TEXTURE_2D, 0, 0, rect->y,
|
qfeglTexSubImage2D (GL_TEXTURE_2D, 0, 0, rect->y,
|
||||||
scrap->size, rect->height, scrap->format,
|
size, rect->height, scrap->format,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
scrap->data + rect->y * scrap->size * scrap->bpp);
|
scrap->data + rect->y * size * scrap->bpp);
|
||||||
VRect_Delete (rect);
|
VRect_Delete (rect);
|
||||||
scrap->batch = 0;
|
scrap->batch = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "QF/plugin/general.h"
|
#include "QF/plugin/general.h"
|
||||||
|
|
||||||
#include "r_internal.h"
|
#include "r_internal.h"
|
||||||
|
#include "r_scrap.h"
|
||||||
#include "vid_internal.h"
|
#include "vid_internal.h"
|
||||||
|
|
||||||
cvar_t *vidrend_plugin;
|
cvar_t *vidrend_plugin;
|
||||||
|
@ -61,6 +62,7 @@ vid_render_funcs_t *r_funcs;
|
||||||
|
|
||||||
#define U __attribute__ ((used))
|
#define U __attribute__ ((used))
|
||||||
static U void (*const r_progs_init)(struct progs_s *) = R_Progs_Init;
|
static U void (*const r_progs_init)(struct progs_s *) = R_Progs_Init;
|
||||||
|
static U void (*const r_scrapdelete)(rscrap_t *) = R_ScrapDelete;
|
||||||
#undef U
|
#undef U
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
183
libs/video/renderer/r_scrap.c
Normal file
183
libs/video/renderer/r_scrap.c
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
r_scrap.c
|
||||||
|
|
||||||
|
Renderer agnostic scrap management
|
||||||
|
|
||||||
|
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
|
||||||
|
|
||||||
|
Author: Bill Currie <bill@taniwha.org>
|
||||||
|
Date: 2021/1/12
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to:
|
||||||
|
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
59 Temple Place - Suite 330
|
||||||
|
Boston, MA 02111-1307, USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "QF/sys.h"
|
||||||
|
#include "QF/vrect.h"
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
|
#include "r_scrap.h"
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
pow2rup (unsigned x)
|
||||||
|
{
|
||||||
|
x--;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
x++;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
R_ScrapInit (rscrap_t *scrap, int width, int height)
|
||||||
|
{
|
||||||
|
width = pow2rup (width);
|
||||||
|
height = pow2rup (height);
|
||||||
|
scrap->width = width;
|
||||||
|
scrap->height = height;
|
||||||
|
scrap->rects = 0;
|
||||||
|
scrap->free_rects = VRect_New (0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
R_ScrapDelete (rscrap_t *scrap)
|
||||||
|
{
|
||||||
|
R_ScrapClear (scrap);
|
||||||
|
VRect_Delete (scrap->free_rects);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE vrect_t *
|
||||||
|
R_ScrapAlloc (rscrap_t *scrap, int width, int height)
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
vrect_t **t, **best;
|
||||||
|
vrect_t *old, *frags, *rect;
|
||||||
|
|
||||||
|
w = pow2rup (width);
|
||||||
|
h = pow2rup (height);
|
||||||
|
|
||||||
|
best = 0;
|
||||||
|
for (t = &scrap->free_rects; *t; t = &(*t)->next) {
|
||||||
|
if ((*t)->width < w || (*t)->height < h)
|
||||||
|
continue; // won't fit
|
||||||
|
if (!best) {
|
||||||
|
best = t;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height)
|
||||||
|
best = t;
|
||||||
|
}
|
||||||
|
if (!best)
|
||||||
|
return 0; // couldn't find a spot
|
||||||
|
old = *best;
|
||||||
|
*best = old->next;
|
||||||
|
rect = VRect_New (old->x, old->y, w, h);
|
||||||
|
frags = VRect_Difference (old, rect);
|
||||||
|
VRect_Delete (old);
|
||||||
|
if (frags) {
|
||||||
|
// old was bigger than the requested size
|
||||||
|
for (old = frags; old->next; old = old->next)
|
||||||
|
;
|
||||||
|
old->next = scrap->free_rects;
|
||||||
|
scrap->free_rects = frags;
|
||||||
|
}
|
||||||
|
rect->next = scrap->rects;
|
||||||
|
scrap->rects = rect;
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
R_ScrapFree (rscrap_t *scrap, vrect_t *rect)
|
||||||
|
{
|
||||||
|
vrect_t *old, *merge;
|
||||||
|
vrect_t **t;
|
||||||
|
|
||||||
|
for (t = &scrap->rects; *t; t = &(*t)->next)
|
||||||
|
if (*t == rect)
|
||||||
|
break;
|
||||||
|
if (*t != rect)
|
||||||
|
Sys_Error ("R_ScrapFree: broken rect");
|
||||||
|
*t = rect->next;
|
||||||
|
|
||||||
|
do {
|
||||||
|
merge = 0;
|
||||||
|
for (t = &scrap->free_rects; *t; t = &(*t)->next) {
|
||||||
|
merge = VRect_Merge (*t, rect);
|
||||||
|
if (merge) {
|
||||||
|
old = *t;
|
||||||
|
*t = (*t)->next;
|
||||||
|
VRect_Delete (old);
|
||||||
|
VRect_Delete (rect);
|
||||||
|
rect = merge;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (merge);
|
||||||
|
rect->next = scrap->free_rects;
|
||||||
|
scrap->free_rects = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
R_ScrapClear (rscrap_t *scrap)
|
||||||
|
{
|
||||||
|
vrect_t *t;
|
||||||
|
|
||||||
|
while (scrap->free_rects) {
|
||||||
|
t = scrap->free_rects;
|
||||||
|
scrap->free_rects = t->next;
|
||||||
|
VRect_Delete (t);
|
||||||
|
}
|
||||||
|
while (scrap->rects) {
|
||||||
|
t = scrap->rects;
|
||||||
|
scrap->rects = t->next;
|
||||||
|
VRect_Delete (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrap->free_rects = VRect_New (0, 0, scrap->width, scrap->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE size_t
|
||||||
|
R_ScrapArea (rscrap_t *scrap)
|
||||||
|
{
|
||||||
|
vrect_t *rect;
|
||||||
|
size_t area;
|
||||||
|
|
||||||
|
for (rect = scrap->free_rects, area = 0; rect; rect = rect->next) {
|
||||||
|
area += rect->width * rect->height;
|
||||||
|
}
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
R_ScrapDump (rscrap_t *scrap)
|
||||||
|
{
|
||||||
|
vrect_t *rect;
|
||||||
|
|
||||||
|
for (rect = scrap->rects; rect; rect = rect->next) {
|
||||||
|
Sys_Printf ("%d %d %d %d\n", rect->x, rect->y,
|
||||||
|
rect->width, rect->height);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue