#include "quakedef.h"
#include "cl_collision.h"
+#include "cl_video.h"
// we need to declare some mouse variables here, because the menu system
// references them even when on a unix system.
CL_Particles_Init();
CL_Screen_Init();
CL_CGVM_Init();
+
+ CL_Video_Init();
}
#include "quakedef.h"
+#include "cl_video.h"
cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
cvar_t scr_fov = {CVAR_SAVE, "fov","90"}; // 10 - 170
r_refdef.drawqueuesize += dq->size;
}
-//only used for the player color selection menu
-void DrawQ_PicTranslate (int x, int y, char *picname, qbyte *translation)
+void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags)
{
- int i, c;
- unsigned int trans[4096];
- cachepic_t *pic;
-
- pic = Draw_CachePic(picname);
- if (pic == NULL)
- return;
-
- c = pic->width * pic->height;
- if (c > 4096)
- {
- Con_Printf("DrawQ_PicTranslate: image larger than 4k buffer\n");
+ int size;
+ void *p;
+ drawqueue_t *dq;
+ drawqueuemesh_t *m;
+ size = sizeof(*dq);
+ size += sizeof(drawqueuemesh_t);
+ size += sizeof(int) * mesh->numindices;
+ size += sizeof(float[3]) * mesh->numvertices;
+ size += sizeof(float[2]) * mesh->numvertices;
+ size += sizeof(float[4]) * mesh->numvertices;
+ if (r_refdef.drawqueuesize + size > MAX_DRAWQUEUE)
return;
- }
-
- for (i = 0;i < c;i++)
- trans[i] = d_8to24table[translation[menuplyr_pixels[i]]];
-
- // FIXME: this is renderer stuff?
- R_UpdateTexture (pic->tex, (qbyte *)trans);
-
- DrawQ_Pic(x, y, picname, 0, 0, 1, 1, 1, 1, 0);
+ dq = (void *)(r_refdef.drawqueue + r_refdef.drawqueuesize);
+ dq->size = size;
+ dq->command = DRAWQUEUE_MESH;
+ dq->flags = flags;
+ dq->color = 0;
+ dq->x = 0;
+ dq->y = 0;
+ dq->scalex = 0;
+ dq->scaley = 0;
+ p = (void *)(dq + 1);
+ m = p;p += sizeof(drawqueuemesh_t);
+ m->numindices = mesh->numindices;
+ m->numvertices = mesh->numvertices;
+ m->texture = mesh->texture;
+ m->indices = p;memcpy(m->indices , mesh->indices , m->numindices * sizeof(int ));p += m->numindices * sizeof(int );
+ m->vertices = p;memcpy(m->vertices , mesh->vertices , m->numvertices * sizeof(float[3]));p += m->numvertices * sizeof(float[3]);
+ m->texcoords = p;memcpy(m->texcoords, mesh->texcoords, m->numvertices * sizeof(float[2]));p += m->numvertices * sizeof(float[2]);
+ m->colors = p;memcpy(m->colors , mesh->colors , m->numvertices * sizeof(float[4]));p += m->numvertices * sizeof(float[4]);
+ r_refdef.drawqueuesize += dq->size;
}
-
/*
====================
CalcFov
SCR_DrawLoading();
}
+ CL_DrawVideo();
+
R_TimeReport("2d");
// add r_speeds text to queue
#define DRAWQUEUE_PIC 0
#define DRAWQUEUE_STRING 1
+#define DRAWQUEUE_MESH 2
typedef struct drawqueue_s
{
}
drawqueue_t;
+// a triangle mesh... embedded in the drawqueue
+typedef struct drawqueuemesh_s
+{
+ rtexture_t *texture;
+ int numindices;
+ int numvertices;
+ int *indices;
+ float *vertices;
+ float *texcoords;
+ qbyte *colors;
+}
+drawqueuemesh_t;
+
#define DRAWFLAG_ADDITIVE 1
+// clear the draw queue
void DrawQ_Clear(void);
+// draw an image
void DrawQ_Pic(float x, float y, char *picname, float width, float height, float red, float green, float blue, float alpha, int flags);
+// draw a text string
void DrawQ_String(float x, float y, char *string, int maxlen, float scalex, float scaley, float red, float green, float blue, float alpha, int flags);
+// draw a filled rectangle
void DrawQ_Fill (float x, float y, float w, float h, float red, float green, float blue, float alpha, int flags);
-// only used for player config menu
-void DrawQ_PicTranslate (int x, int y, char *picname, qbyte *translation);
+// draw a triangle mesh
+void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags);
void SHOWLMP_decodehide(void);
void SHOWLMP_decodeshow(void);
--- /dev/null
+
+#include "quakedef.h"
+#include "cl_video.h"
+#include "dpvsimpledecode.h"
+
+mempool_t *clvideomempool;
+
+int cl_videoplaying = false;
+void *cl_videostream;
+
+double cl_videostarttime;
+int cl_videoframenum;
+double cl_videoframerate;
+
+int cl_videoimagewidth;
+int cl_videoimageheight;
+int cl_videoimagedata_rmask;
+int cl_videoimagedata_gmask;
+int cl_videoimagedata_bmask;
+int cl_videoimagedata_bytesperpixel;
+void *cl_videoimagedata;
+
+int cl_videosoundrate;
+int cl_videosoundlength;
+short *cl_videosounddata;
+int cl_videosoundresamplelength;
+short *cl_videosoundresampledata;
+
+rtexture_t *cl_videotexture;
+rtexturepool_t *cl_videotexturepool;
+
+void CL_VideoFrame(void)
+{
+ int frames, framenum, samples, s;
+ if (!cl_videoplaying)
+ return;
+ framenum = (realtime - cl_videostarttime) * cl_videoframerate;
+ //Con_Printf("frame %i\n", framenum);
+ if (framenum < 0)
+ framenum = 0;
+ frames = 0;
+ while (cl_videoframenum < framenum)
+ {
+ frames++;
+ cl_videoframenum++;
+ if (dpvsimpledecode_video(cl_videostream, cl_videoimagedata, cl_videoimagedata_rmask, cl_videoimagedata_gmask, cl_videoimagedata_bmask, cl_videoimagedata_bytesperpixel, cl_videoimagewidth * cl_videoimagedata_bytesperpixel))
+ {
+ CL_VideoStop();
+ return;
+ }
+ }
+ if (frames)
+ {
+ R_UpdateTexture(cl_videotexture, cl_videoimagedata);
+ //Draw_NewPic("engine_videoframe", cl_videoimagewidth, cl_videoimageheight, false, cl_videoimagedata);
+ }
+ if (cl_videosoundrate && (samples = S_RawSamples_QueueWantsMore()))
+ {
+ Con_Printf("%i = S_RawSamples_QueueWantsMore()\n", samples);
+
+ // calculate how much source data we need to fill the output...
+ s = samples * cl_videosoundrate / shm->speed;
+
+ // reallocate processing buffer if needed
+ if (cl_videosoundresamplelength < samples)
+ {
+ cl_videosoundresamplelength = samples + 100;
+ if (cl_videosoundresampledata)
+ Mem_Free(cl_videosoundresampledata);
+ cl_videosoundresampledata = Mem_Alloc(clvideomempool, cl_videosoundresamplelength * sizeof(short[2]));
+ }
+
+ // reallocate loading buffer if needed
+ if (cl_videosoundlength < s)
+ {
+ cl_videosoundlength = s + 100;
+ if (cl_videosounddata)
+ Mem_Free(cl_videosounddata);
+ cl_videosounddata = Mem_Alloc(clvideomempool, cl_videosoundlength * sizeof(short[2]));
+ }
+
+ dpvsimpledecode_audio(cl_videostream, cl_videosounddata, s);
+ S_ResampleBuffer16Stereo(cl_videosounddata, s, cl_videosoundresampledata, samples);
+ S_RawSamples_Enqueue(cl_videosoundresampledata, samples);
+ }
+}
+
+void CL_DrawVideo(void)
+{
+ if (cl_videoplaying)
+ {
+ drawqueuemesh_t mesh;
+ int indices[6];
+ float vertices[12];
+ float texcoords[8];
+ qbyte colorsb[16];
+ float s1, t1, s2, t2, x1, y1, x2, y2;
+ indices[0] = 0;
+ indices[1] = 1;
+ indices[2] = 2;
+ indices[3] = 0;
+ indices[4] = 2;
+ indices[5] = 3;
+ x1 = 0;
+ y1 = 0;
+ x2 = vid.conwidth;
+ y2 = vid.conheight;
+ vertices[0] = y1;
+ vertices[1] = y1;
+ vertices[2] = 0;
+ vertices[3] = x2;
+ vertices[4] = y1;
+ vertices[5] = 0;
+ vertices[6] = x2;
+ vertices[7] = y2;
+ vertices[8] = 0;
+ vertices[9] = x1;
+ vertices[10] = y2;
+ vertices[11] = 0;
+ R_FragmentLocation(cl_videotexture, NULL, NULL, &s1, &t1, &s2, &t2);
+ texcoords[0] = s1;
+ texcoords[1] = t1;
+ texcoords[2] = s2;
+ texcoords[3] = t1;
+ texcoords[4] = s2;
+ texcoords[5] = t2;
+ texcoords[6] = s1;
+ texcoords[7] = t2;
+ colorsb[0] = 255 >> v_overbrightbits.integer;
+ colorsb[1] = 255 >> v_overbrightbits.integer;
+ colorsb[2] = 255 >> v_overbrightbits.integer;
+ colorsb[3] = 255;
+ colorsb[4] = 255 >> v_overbrightbits.integer;
+ colorsb[5] = 255 >> v_overbrightbits.integer;
+ colorsb[6] = 255 >> v_overbrightbits.integer;
+ colorsb[7] = 255;
+ colorsb[8] = 255 >> v_overbrightbits.integer;
+ colorsb[9] = 255 >> v_overbrightbits.integer;
+ colorsb[10] = 255 >> v_overbrightbits.integer;
+ colorsb[11] = 255;
+ colorsb[12] = 255 >> v_overbrightbits.integer;
+ colorsb[13] = 255 >> v_overbrightbits.integer;
+ colorsb[14] = 255 >> v_overbrightbits.integer;
+ colorsb[15] = 255;
+ mesh.texture = cl_videotexture;
+ mesh.numindices = 6;
+ mesh.numvertices = 4;
+ mesh.indices = indices;
+ mesh.vertices = vertices;
+ mesh.texcoords = texcoords;
+ mesh.colors = colorsb;
+ DrawQ_Mesh(&mesh, 0);
+ //DrawQ_Pic(0, 0, "engine_videoframe", vid.conwidth, vid.conheight, 1, 1, 1, 1, 0);
+ }
+}
+
+void CL_VideoStart(char *filename)
+{
+ char *errorstring;
+ cl_videostream = dpvsimpledecode_open(filename, &errorstring);
+ if (!cl_videostream)
+ {
+ Con_Printf("unable to open \"%s\", error: %s\n", filename, errorstring);
+ return;
+ }
+
+ cl_videoplaying = true;
+ cl_videostarttime = realtime;
+ cl_videoframenum = -1;
+ cl_videoframerate = dpvsimpledecode_getframerate(cl_videostream);
+ cl_videoimagewidth = dpvsimpledecode_getwidth(cl_videostream);
+ cl_videoimageheight = dpvsimpledecode_getheight(cl_videostream);
+
+ // RGBA format
+ cl_videoimagedata_bytesperpixel = 4;
+ cl_videoimagedata_rmask = BigLong(0xFF000000);
+ cl_videoimagedata_gmask = BigLong(0x00FF0000);
+ cl_videoimagedata_bmask = BigLong(0x0000FF00);
+ cl_videoimagedata = Mem_Alloc(clvideomempool, cl_videoimagewidth * cl_videoimageheight * cl_videoimagedata_bytesperpixel);
+ //memset(cl_videoimagedata, 97, cl_videoimagewidth * cl_videoimageheight * cl_videoimagedata_bytesperpixel);
+
+ cl_videosoundrate = dpvsimpledecode_getsoundrate(cl_videostream);
+ cl_videosoundlength = 0;
+ cl_videosounddata = NULL;
+ cl_videosoundresamplelength = 0;
+ cl_videosoundresampledata = NULL;
+
+ cl_videotexturepool = R_AllocTexturePool();
+ cl_videotexture = R_LoadTexture(cl_videotexturepool, "videotexture", cl_videoimagewidth, cl_videoimageheight, NULL, TEXTYPE_RGBA, 0);
+}
+
+void CL_VideoStop(void)
+{
+ cl_videoplaying = false;
+
+ if (cl_videostream)
+ dpvsimpledecode_close(cl_videostream);
+ cl_videostream = NULL;
+
+ if (cl_videoimagedata)
+ Mem_Free(cl_videoimagedata);
+ cl_videoimagedata = NULL;
+
+ if (cl_videosounddata)
+ Mem_Free(cl_videosounddata);
+ cl_videosounddata = NULL;
+
+ if (cl_videosoundresampledata)
+ Mem_Free(cl_videosoundresampledata);
+ cl_videosoundresampledata = NULL;
+
+ cl_videotexture = NULL;
+ R_FreeTexturePool(&cl_videotexturepool);
+
+ Draw_FreePic("engine_videoframe");
+}
+
+static void CL_PlayVideo_f(void)
+{
+ char name[1024];
+
+ if (Cmd_Argc() != 2)
+ {
+ Con_Printf ("usage: playvideo <videoname>\nplays video named video/<videoname>.dpv\n");
+ return;
+ }
+
+ sprintf(name, "%s/video/%s.dpv", com_gamedir, Cmd_Argv(1));
+ CL_VideoStart(name);
+}
+
+static void CL_StopVideo_f(void)
+{
+ CL_VideoStop();
+}
+
+void CL_Video_Init(void)
+{
+ Cmd_AddCommand("playvideo", CL_PlayVideo_f);
+ Cmd_AddCommand("stopvideo", CL_StopVideo_f);
+
+ clvideomempool = Mem_AllocPool("CL_Video");
+}
--- /dev/null
+
+#ifndef CL_VIDEO_H
+#define CL_VIDEO_H
+
+extern int cl_videoplaying;
+void CL_VideoFrame(void);
+void CL_DrawVideo(void);
+void CL_VideoStart(char *filename);
+void CL_VideoStop(void);
+void CL_Video_Init(void);
+
+#endif
CFG=darkplaces - Win32 Debug\r
!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
!MESSAGE use the Export Makefile command and run\r
-!MESSAGE \r
+!MESSAGE\r
!MESSAGE NMAKE /f "darkplaces.mak".\r
-!MESSAGE \r
+!MESSAGE\r
!MESSAGE You can specify a configuration when running NMAKE\r
!MESSAGE by defining the macro CFG on the command line. For example:\r
-!MESSAGE \r
+!MESSAGE\r
!MESSAGE NMAKE /f "darkplaces.mak" CFG="darkplaces - Win32 Debug"\r
-!MESSAGE \r
+!MESSAGE\r
!MESSAGE Possible choices for configuration are:\r
!MESSAGE \r
!MESSAGE "darkplaces - Win32 Release" (based on "Win32 (x86) Application")\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\cl_video.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\cmd.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\dpvsimpledecode.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\filematch.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\wavefile.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\world.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\cl_video.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\client.h\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\dpvsimpledecode.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\draw.h\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=.\wavefile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\winquake.h\r
# End Source File\r
# Begin Source File\r
--- /dev/null
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include "dpvsimpledecode.h"
+#include "wavefile.h"
+
+#define EMBEDDEDHZREAD 1
+
+#ifndef EMBEDDEDHZREAD
+#include "hz_read.h"
+#include "hz_read.c"
+#else
+#define HZREADERROR_OK 0
+#define HZREADERROR_EOF 1
+#define HZREADERROR_MALLOCFAILED 2
+
+#define HZREADBLOCKSIZE 16000
+
+typedef struct
+{
+ FILE *file;
+ int endoffile;
+}
+hz_bitstream_read_t;
+
+typedef struct hz_bitstream_readblock_s
+{
+ struct hz_bitstream_readblock_s *next;
+ unsigned int size;
+ unsigned char data[HZREADBLOCKSIZE];
+}
+hz_bitstream_readblock_t;
+
+typedef struct
+{
+ hz_bitstream_readblock_t *blocks;
+ hz_bitstream_readblock_t *current;
+ unsigned int position;
+ unsigned int store;
+ int count;
+}
+hz_bitstream_readblocks_t;
+
+hz_bitstream_read_t *hz_bitstream_read_open(char *filename)
+{
+ FILE *file;
+ hz_bitstream_read_t *stream;
+ if ((file = fopen(filename, "rb")))
+ {
+ stream = malloc(sizeof(hz_bitstream_read_t));
+ memset(stream, 0, sizeof(*stream));
+ stream->file = file;
+ return stream;
+ }
+ else
+ return NULL;
+}
+
+void hz_bitstream_read_close(hz_bitstream_read_t *stream)
+{
+ if (stream)
+ {
+ fclose(stream->file);
+ free(stream);
+ }
+}
+
+unsigned int hz_bitstream_read_currentbyte(hz_bitstream_read_t *stream)
+{
+ return ftell(stream->file);
+}
+
+int hz_bitstream_read_seek(hz_bitstream_read_t *stream, unsigned int position)
+{
+ stream->endoffile = 0;
+ return fseek(stream->file, position, SEEK_SET) != 0;
+}
+
+hz_bitstream_readblocks_t *hz_bitstream_read_blocks_new(void)
+{
+ hz_bitstream_readblocks_t *blocks;
+ blocks = malloc(sizeof(hz_bitstream_readblocks_t));
+ if (blocks == NULL)
+ return NULL;
+ memset(blocks, 0, sizeof(hz_bitstream_readblocks_t));
+ return blocks;
+}
+
+void hz_bitstream_read_blocks_free(hz_bitstream_readblocks_t *blocks)
+{
+ hz_bitstream_readblock_t *b, *n;
+ if (blocks == NULL)
+ return;
+ for (b = blocks->blocks;b;b = n)
+ {
+ n = b->next;
+ free(b);
+ }
+ free(blocks);
+}
+
+void hz_bitstream_read_flushbits(hz_bitstream_readblocks_t *blocks)
+{
+ blocks->store = 0;
+ blocks->count = 0;
+}
+
+int hz_bitstream_read_blocks_read(hz_bitstream_readblocks_t *blocks, hz_bitstream_read_t *stream, unsigned int size)
+{
+ int s;
+ hz_bitstream_readblock_t *b, *p;
+ s = size;
+ p = NULL;
+ b = blocks->blocks;
+ while (s > 0)
+ {
+ if (b == NULL)
+ {
+ b = malloc(sizeof(hz_bitstream_readblock_t));
+ if (b == NULL)
+ return HZREADERROR_MALLOCFAILED;
+ b->next = NULL;
+ b->size = 0;
+ if (p != NULL)
+ p->next = b;
+ else
+ blocks->blocks = b;
+ }
+ if (s > HZREADBLOCKSIZE)
+ b->size = HZREADBLOCKSIZE;
+ else
+ b->size = s;
+ s -= b->size;
+ if (fread(b->data, 1, b->size, stream->file) != b->size)
+ {
+ stream->endoffile = 1;
+ break;
+ }
+ p = b;
+ b = b->next;
+ }
+ while (b)
+ {
+ b->size = 0;
+ b = b->next;
+ }
+ blocks->current = blocks->blocks;
+ blocks->position = 0;
+ hz_bitstream_read_flushbits(blocks);
+ if (stream->endoffile)
+ return HZREADERROR_EOF;
+ return HZREADERROR_OK;
+}
+
+unsigned int hz_bitstream_read_blocks_getbyte(hz_bitstream_readblocks_t *blocks)
+{
+ while (blocks->current != NULL && blocks->position >= blocks->current->size)
+ {
+ blocks->position = 0;
+ blocks->current = blocks->current->next;
+ }
+ if (blocks->current == NULL)
+ return 0;
+ return blocks->current->data[blocks->position++];
+}
+
+int hz_bitstream_read_bit(hz_bitstream_readblocks_t *blocks)
+{
+ if (!blocks->count)
+ {
+ blocks->count += 8;
+ blocks->store <<= 8;
+ blocks->store |= hz_bitstream_read_blocks_getbyte(blocks) & 0xFF;
+ }
+ blocks->count--;
+ return (blocks->store >> blocks->count) & 1;
+}
+
+unsigned int hz_bitstream_read_bits(hz_bitstream_readblocks_t *blocks, unsigned int size)
+{
+ unsigned int num = 0;
+ // we can only handle about 24 bits at a time safely
+ // (there might be up to 7 bits more than we need in the bit store)
+ if (size > 24)
+ {
+ size -= 8;
+ num |= hz_bitstream_read_bits(blocks, 8) << size;
+ }
+ while (blocks->count < size)
+ {
+ blocks->count += 8;
+ blocks->store <<= 8;
+ blocks->store |= hz_bitstream_read_blocks_getbyte(blocks) & 0xFF;
+ }
+ blocks->count -= size;
+ num |= (blocks->store >> blocks->count) & ((1 << size) - 1);
+ return num;
+}
+
+unsigned int hz_bitstream_read_byte(hz_bitstream_readblocks_t *blocks)
+{
+ return hz_bitstream_read_blocks_getbyte(blocks);
+}
+
+unsigned int hz_bitstream_read_short(hz_bitstream_readblocks_t *blocks)
+{
+ return (hz_bitstream_read_byte(blocks) << 8)
+ | (hz_bitstream_read_byte(blocks));
+}
+
+unsigned int hz_bitstream_read_int(hz_bitstream_readblocks_t *blocks)
+{
+ return (hz_bitstream_read_byte(blocks) << 24)
+ | (hz_bitstream_read_byte(blocks) << 16)
+ | (hz_bitstream_read_byte(blocks) << 8)
+ | (hz_bitstream_read_byte(blocks));
+}
+
+void hz_bitstream_read_bytes(hz_bitstream_readblocks_t *blocks, void *outdata, unsigned int size)
+{
+ unsigned char *out;
+ out = outdata;
+ while (size--)
+ *out++ = hz_bitstream_read_byte(blocks);
+}
+#endif
+
+#define BLOCKSIZE 8
+
+typedef struct dpvsimpledecodestream_s
+{
+ hz_bitstream_read_t *bitstream;
+ hz_bitstream_readblocks_t *framedatablocks;
+
+ int error;
+
+ double info_framerate;
+ unsigned int info_frames;
+
+ unsigned int info_imagewidth;
+ unsigned int info_imageheight;
+ unsigned int info_imagebpp;
+ unsigned int info_imageRloss;
+ unsigned int info_imageRmask;
+ unsigned int info_imageRshift;
+ unsigned int info_imageGloss;
+ unsigned int info_imageGmask;
+ unsigned int info_imageGshift;
+ unsigned int info_imageBloss;
+ unsigned int info_imageBmask;
+ unsigned int info_imageBshift;
+ unsigned int info_imagesize;
+
+ // current video frame (needed because of delta compression)
+ int videoframenum;
+ // current video frame data (needed because of delta compression)
+ unsigned int *videopixels;
+
+ // wav file the sound is being read from
+ wavefile_t *wavefile;
+}
+dpvsimpledecodestream_t;
+
+static int dpvsimpledecode_setpixelformat(dpvsimpledecodestream_t *s, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel)
+{
+ int Rshift, Rbits, Gshift, Gbits, Bshift, Bbits;
+ if (!Rmask)
+ {
+ s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK;
+ return s->error;
+ }
+ if (!Gmask)
+ {
+ s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK;
+ return s->error;
+ }
+ if (!Bmask)
+ {
+ s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK;
+ return s->error;
+ }
+ if (Rmask & Gmask || Rmask & Bmask || Gmask & Bmask)
+ {
+ s->error = DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP;
+ return s->error;
+ }
+ switch (bytesperpixel)
+ {
+ case 2:
+ if ((Rmask | Gmask | Bmask) > 65536)
+ {
+ s->error = DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP;
+ return s->error;
+ }
+ break;
+ case 4:
+ break;
+ default:
+ s->error = DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP;
+ return s->error;
+ break;
+ }
+ for (Rshift = 0;!(Rmask & 1);Rshift++, Rmask >>= 1);
+ for (Gshift = 0;!(Gmask & 1);Gshift++, Gmask >>= 1);
+ for (Bshift = 0;!(Bmask & 1);Bshift++, Bmask >>= 1);
+ if (((Rmask + 1) & Rmask) != 0)
+ {
+ s->error = DPVSIMPLEDECODEERROR_INVALIDRMASK;
+ return s->error;
+ }
+ if (((Gmask + 1) & Gmask) != 0)
+ {
+ s->error = DPVSIMPLEDECODEERROR_INVALIDGMASK;
+ return s->error;
+ }
+ if (((Bmask + 1) & Bmask) != 0)
+ {
+ s->error = DPVSIMPLEDECODEERROR_INVALIDBMASK;
+ return s->error;
+ }
+ for (Rbits = 0;Rmask & 1;Rbits++, Rmask >>= 1);
+ for (Gbits = 0;Gmask & 1;Gbits++, Gmask >>= 1);
+ for (Bbits = 0;Bmask & 1;Bbits++, Bmask >>= 1);
+ if (Rbits > 8)
+ {
+ Rshift += (Rbits - 8);
+ Rbits = 8;
+ }
+ if (Gbits > 8)
+ {
+ Gshift += (Gbits - 8);
+ Gbits = 8;
+ }
+ if (Bbits > 8)
+ {
+ Bshift += (Bbits - 8);
+ Bbits = 8;
+ }
+ s->info_imagebpp = bytesperpixel;
+ s->info_imageRloss = 16 + (8 - Rbits);
+ s->info_imageGloss = 8 + (8 - Gbits);
+ s->info_imageBloss = 0 + (8 - Bbits);
+ s->info_imageRmask = (1 << Rbits) - 1;
+ s->info_imageGmask = (1 << Gbits) - 1;
+ s->info_imageBmask = (1 << Bbits) - 1;
+ s->info_imageRshift = Rshift;
+ s->info_imageGshift = Gshift;
+ s->info_imageBshift = Bshift;
+ s->info_imagesize = s->info_imagewidth * s->info_imageheight * s->info_imagebpp;
+ return s->error;
+}
+
+// opening and closing streams
+
+static void StripExtension(char *in, char *out)
+{
+ char *dot, *c;
+ dot = NULL;
+ for (c = in;*c;c++)
+ {
+ if (*c == ':' || *c == '\\' || *c == '/')
+ dot = NULL;
+ if (*c == '.')
+ dot = c;
+ }
+ if (dot == NULL)
+ {
+ // nothing to remove
+ strcpy(out, in);
+ return;
+ }
+ else
+ {
+ memcpy(out, in, dot - in);
+ out[dot - in] = 0;
+ }
+}
+
+// opens a stream
+void *dpvsimpledecode_open(char *filename, char **errorstring)
+{
+ dpvsimpledecodestream_t *s;
+ char t[8], *wavename;
+ if (errorstring != NULL)
+ *errorstring = NULL;
+ s = malloc(sizeof(dpvsimpledecodestream_t));
+ if (s != NULL)
+ {
+ s->bitstream = hz_bitstream_read_open(filename);
+ if (s->bitstream != NULL)
+ {
+ // check file identification
+ s->framedatablocks = hz_bitstream_read_blocks_new();
+ if (s->framedatablocks != NULL)
+ {
+ hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8);
+ hz_bitstream_read_bytes(s->framedatablocks, t, 8);
+ if (!memcmp(t, "DPVideo", 8))
+ {
+ // check version number
+ hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 2);
+ if (hz_bitstream_read_short(s->framedatablocks) == 1)
+ {
+ hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 12);
+ s->info_imagewidth = hz_bitstream_read_short(s->framedatablocks);
+ s->info_imageheight = hz_bitstream_read_short(s->framedatablocks);
+ s->info_framerate = (double) hz_bitstream_read_int(s->framedatablocks) * (1.0 / 65536.0);
+
+ if (s->info_framerate > 0.0)
+ {
+ s->videopixels = malloc(s->info_imagewidth * s->info_imageheight * sizeof(*s->videopixels));
+ if (s->videopixels != NULL)
+ {
+ wavename = malloc(strlen(filename) + 10);
+ if (wavename)
+ {
+ StripExtension(filename, wavename);
+ strcat(wavename, ".wav");
+ s->wavefile = waveopen(wavename, NULL);
+ free(wavename);
+ }
+ // all is well...
+ s->videoframenum = -10000;
+ return s;
+ }
+ else if (errorstring != NULL)
+ *errorstring = "unable to allocate video image buffer";
+ }
+ else if (errorstring != NULL)
+ *errorstring = "error in video info chunk";
+ }
+ else if (errorstring != NULL)
+ *errorstring = "read error";
+ }
+ else if (errorstring != NULL)
+ *errorstring = "not a dpvideo file";
+ hz_bitstream_read_blocks_free(s->framedatablocks);
+ }
+ else if (errorstring != NULL)
+ *errorstring = "unable to allocate memory for reading buffer";
+ hz_bitstream_read_close(s->bitstream);
+ }
+ else if (errorstring != NULL)
+ *errorstring = "unable to open file";
+ free(s);
+ }
+ else if (errorstring != NULL)
+ *errorstring = "unable to allocate memory for stream info structure";
+ return NULL;
+}
+
+// closes a stream
+void dpvsimpledecode_close(void *stream)
+{
+ dpvsimpledecodestream_t *s = stream;
+ if (s == NULL)
+ return;
+ if (s->videopixels)
+ free(s->videopixels);
+ if (s->wavefile)
+ waveclose(s->wavefile);
+ if (s->framedatablocks)
+ hz_bitstream_read_blocks_free(s->framedatablocks);
+ if (s->bitstream)
+ hz_bitstream_read_close(s->bitstream);
+ free(s);
+}
+
+// utilitarian functions
+
+// returns the current error number for the stream, and resets the error
+// number to DPVSIMPLEDECODEERROR_NONE
+// if the supplied string pointer variable is not NULL, it will be set to the
+// error message
+int dpvsimpledecode_error(void *stream, char **errorstring)
+{
+ dpvsimpledecodestream_t *s = stream;
+ int e;
+ e = s->error;
+ s->error = 0;
+ if (errorstring)
+ {
+ switch (e)
+ {
+ case DPVSIMPLEDECODEERROR_NONE:
+ *errorstring = "no error";
+ break;
+ case DPVSIMPLEDECODEERROR_EOF:
+ *errorstring = "end of file reached (this is not an error)";
+ break;
+ case DPVSIMPLEDECODEERROR_READERROR:
+ *errorstring = "read error (corrupt or incomplete file)";
+ break;
+ case DPVSIMPLEDECODEERROR_SOUNDBUFFERTOOSMALL:
+ *errorstring = "sound buffer is too small for decoding frame (please allocate it as large as dpvsimpledecode_getneededsoundbufferlength suggests)";
+ break;
+ case DPVSIMPLEDECODEERROR_INVALIDRMASK:
+ *errorstring = "invalid red bits mask";
+ break;
+ case DPVSIMPLEDECODEERROR_INVALIDGMASK:
+ *errorstring = "invalid green bits mask";
+ break;
+ case DPVSIMPLEDECODEERROR_INVALIDBMASK:
+ *errorstring = "invalid blue bits mask";
+ break;
+ case DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP:
+ *errorstring = "color bit masks overlap";
+ break;
+ case DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP:
+ *errorstring = "color masks too big for specified bytes per pixel";
+ break;
+ case DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP:
+ *errorstring = "unsupported bytes per pixel (must be 2 for 16bit, or 4 for 32bit)";
+ break;
+ default:
+ *errorstring = "unknown error";
+ break;
+ }
+ }
+ return e;
+}
+
+// returns the width of the image data
+unsigned int dpvsimpledecode_getwidth(void *stream)
+{
+ dpvsimpledecodestream_t *s = stream;
+ return s->info_imagewidth;
+}
+
+// returns the height of the image data
+unsigned int dpvsimpledecode_getheight(void *stream)
+{
+ dpvsimpledecodestream_t *s = stream;
+ return s->info_imageheight;
+}
+
+// returns the sound sample rate of the stream
+unsigned int dpvsimpledecode_getsoundrate(void *stream)
+{
+ dpvsimpledecodestream_t *s = stream;
+ if (s->wavefile)
+ return s->wavefile->info_rate;
+ else
+ return 0;
+}
+
+// returns the framerate of the stream
+double dpvsimpledecode_getframerate(void *stream)
+{
+ dpvsimpledecodestream_t *s = stream;
+ return s->info_framerate;
+}
+
+
+
+
+
+static int dpvsimpledecode_convertpixels(dpvsimpledecodestream_t *s, void *imagedata, int imagebytesperrow)
+{
+ unsigned int a, x, y, width, height;
+ unsigned int Rloss, Rmask, Rshift, Gloss, Gmask, Gshift, Bloss, Bmask, Bshift;
+ unsigned int *in;
+
+ width = s->info_imagewidth;
+ height = s->info_imageheight;
+
+ Rloss = s->info_imageRloss;
+ Rmask = s->info_imageRmask;
+ Rshift = s->info_imageRshift;
+ Gloss = s->info_imageGloss;
+ Gmask = s->info_imageGmask;
+ Gshift = s->info_imageGshift;
+ Bloss = s->info_imageBloss;
+ Bmask = s->info_imageBmask;
+ Bshift = s->info_imageBshift;
+
+ in = s->videopixels;
+ if (s->info_imagebpp == 4)
+ {
+ unsigned int *outrow;
+ for (y = 0;y < height;y++)
+ {
+ outrow = (void *)((unsigned char *)imagedata + y * imagebytesperrow);
+ for (x = 0;x < width;x++)
+ {
+ a = *in++;
+ outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift);
+ }
+ }
+ }
+ else
+ {
+ unsigned short *outrow;
+ for (y = 0;y < height;y++)
+ {
+ outrow = (void *)((unsigned char *)imagedata + y * imagebytesperrow);
+ if (Rloss == 19 && Gloss == 10 && Bloss == 3 && Rshift == 11 && Gshift == 5 && Bshift == 0)
+ {
+ // optimized
+ for (x = 0;x < width;x++)
+ {
+ a = *in++;
+ outrow[x] = ((a >> 8) & 0xF800) | ((a >> 5) & 0x07E0) | ((a >> 3) & 0x001F);
+ }
+ }
+ else
+ {
+ for (x = 0;x < width;x++)
+ {
+ a = *in++;
+ outrow[x] = (((a >> Rloss) & Rmask) << Rshift) | (((a >> Gloss) & Gmask) << Gshift) | (((a >> Bloss) & Bmask) << Bshift);
+ }
+ }
+ }
+ }
+ return s->error;
+}
+
+static int dpvsimpledecode_decompressimage(dpvsimpledecodestream_t *s)
+{
+ int i, a, b, colors, g, x1, y1, bw, bh, width, height, palettebits;
+ unsigned int palette[256], *outrow, *out;
+ g = BLOCKSIZE;
+ width = s->info_imagewidth;
+ height = s->info_imageheight;
+ for (y1 = 0;y1 < height;y1 += g)
+ {
+ outrow = s->videopixels + y1 * width;
+ bh = g;
+ if (y1 + bh > height)
+ bh = height - y1;
+ for (x1 = 0;x1 < width;x1 += g)
+ {
+ out = outrow + x1;
+ bw = g;
+ if (x1 + bw > width)
+ bw = width - x1;
+ if (hz_bitstream_read_bit(s->framedatablocks))
+ {
+ // updated block
+ palettebits = hz_bitstream_read_bits(s->framedatablocks, 3);
+ colors = 1 << palettebits;
+ for (i = 0;i < colors;i++)
+ palette[i] = hz_bitstream_read_bits(s->framedatablocks, 24);
+ if (palettebits)
+ {
+ for (b = 0;b < bh;b++, out += width)
+ for (a = 0;a < bw;a++)
+ out[a] = palette[hz_bitstream_read_bits(s->framedatablocks, palettebits)];
+ }
+ else
+ {
+ for (b = 0;b < bh;b++, out += width)
+ for (a = 0;a < bw;a++)
+ out[a] = palette[0];
+ }
+ }
+ }
+ }
+ return s->error;
+}
+
+// decodes a video frame to the supplied output pixels
+int dpvsimpledecode_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)
+{
+ dpvsimpledecodestream_t *s = stream;
+ unsigned int framedatasize;
+ char t[4];
+ s->error = DPVSIMPLEDECODEERROR_NONE;
+ if (dpvsimpledecode_setpixelformat(s, Rmask, Gmask, Bmask, bytesperpixel))
+ return s->error;
+
+ hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, 8);
+ hz_bitstream_read_bytes(s->framedatablocks, t, 4);
+ if (memcmp(t, "VID0", 4))
+ {
+ if (t[0] == 0)
+ return (s->error = DPVSIMPLEDECODEERROR_EOF);
+ else
+ return (s->error = DPVSIMPLEDECODEERROR_READERROR);
+ }
+ framedatasize = hz_bitstream_read_int(s->framedatablocks);
+ hz_bitstream_read_blocks_read(s->framedatablocks, s->bitstream, framedatasize);
+ if (dpvsimpledecode_decompressimage(s))
+ return s->error;
+
+ dpvsimpledecode_convertpixels(s, imagedata, imagebytesperrow);
+ return s->error;
+}
+
+// (note: sound is 16bit stereo native-endian, left channel first)
+int dpvsimpledecode_audio(void *stream, short *soundbuffer, int requestedlength)
+{
+ int samples;
+ dpvsimpledecodestream_t *s = stream;
+ s->error = DPVSIMPLEDECODEERROR_NONE;
+ if (requestedlength)
+ {
+ samples = 0;
+ if (s->wavefile && requestedlength)
+ samples = waveread16stereo(s->wavefile, soundbuffer, requestedlength);
+ if (samples < requestedlength)
+ memset(soundbuffer + samples * 2, 0, (requestedlength - samples) * sizeof(short[2]));
+ }
+ return s->error;
+}
--- /dev/null
+
+#ifndef DPVSIMPLEDECODE_H
+#define DPVSIMPLEDECODE_H
+
+#define DPVSIMPLEDECODEERROR_NONE 0
+#define DPVSIMPLEDECODEERROR_EOF 1
+#define DPVSIMPLEDECODEERROR_READERROR 2
+#define DPVSIMPLEDECODEERROR_SOUNDBUFFERTOOSMALL 3
+#define DPVSIMPLEDECODEERROR_INVALIDRMASK 4
+#define DPVSIMPLEDECODEERROR_INVALIDGMASK 5
+#define DPVSIMPLEDECODEERROR_INVALIDBMASK 6
+#define DPVSIMPLEDECODEERROR_COLORMASKSOVERLAP 7
+#define DPVSIMPLEDECODEERROR_COLORMASKSEXCEEDBPP 8
+#define DPVSIMPLEDECODEERROR_UNSUPPORTEDBPP 9
+
+// opening and closing streams
+
+// opens a stream
+void *dpvsimpledecode_open(char *filename, char **errorstring);
+// closes a stream
+void dpvsimpledecode_close(void *stream);
+
+// utilitarian functions
+
+// returns the current error number for the stream, and resets the error
+// number to DPVDECODEERROR_NONE
+// if the supplied string pointer variable is not NULL, it will be set to the
+// error message
+int dpvsimpledecode_error(void *stream, char **errorstring);
+
+// returns the width of the image data
+unsigned int dpvsimpledecode_getwidth(void *stream);
+
+// returns the height of the image data
+unsigned int dpvsimpledecode_getheight(void *stream);
+
+// returns the sound sample rate of the stream
+unsigned int dpvsimpledecode_getsoundrate(void *stream);
+
+// returns the framerate of the stream
+double dpvsimpledecode_getframerate(void *stream);
+
+// decodes a video frame to the supplied output pixels
+int dpvsimpledecode_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);
+// reads some sound
+// (note: sound is 16bit stereo native-endian, left channel first)
+int dpvsimpledecode_audio(void *stream, short *soundbuffer, int requestedlength);
+
+#endif
void Draw_Init (void);
cachepic_t *Draw_CachePic (char *path);
+// create or update a pic's image
+cachepic_t *Draw_NewPic(char *picname, int width, int height, int alpha, qbyte *pixels);
+// free the texture memory used by a pic
+void Draw_FreePic(char *picname);
void R_DrawQueue(void);
return pic;
}
+cachepic_t *Draw_NewPic(char *picname, int width, int height, int alpha, qbyte *pixels)
+{
+ int crc, hashkey;
+ cachepic_t *pic;
+
+ crc = CRC_Block(picname, strlen(picname));
+ hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
+ for (pic = cachepichash[hashkey];pic;pic = pic->chain)
+ if (!strcmp (picname, pic->name))
+ break;
+
+ if (pic)
+ {
+ if (pic->tex && R_TextureWidth(pic->tex) == width && R_TextureHeight(pic->tex) == height && (R_TextureHasAlpha(pic->tex) != 0) == (alpha != 0))
+ {
+ R_UpdateTexture(pic->tex, pixels);
+ return pic;
+ }
+ }
+ else
+ {
+ if (pic == NULL)
+ {
+ if (numcachepics == MAX_CACHED_PICS)
+ Sys_Error ("numcachepics == MAX_CACHED_PICS");
+ pic = cachepics + (numcachepics++);
+ strcpy (pic->name, picname);
+ // link into list
+ pic->chain = cachepichash[hashkey];
+ cachepichash[hashkey] = pic;
+ }
+ }
+
+ pic->width = width;
+ pic->height = height;
+ if (pic->tex)
+ R_FreeTexture(pic->tex);
+ pic->tex = R_LoadTexture (drawtexturepool, picname, width, height, pixels, TEXTYPE_RGBA, alpha ? TEXF_ALPHA : 0);
+ return pic;
+}
+
+void Draw_FreePic(char *picname)
+{
+ int crc;
+ int hashkey;
+ cachepic_t *pic;
+ // this doesn't really free the pic, but does free it's texture
+ crc = CRC_Block(picname, strlen(picname));
+ hashkey = ((crc >> 8) ^ crc) % CACHEPICHASHSIZE;
+ for (pic = cachepichash[hashkey];pic;pic = pic->chain)
+ {
+ if (!strcmp (picname, pic->name))
+ {
+ R_FreeTexture(pic->tex);
+ pic->width = 0;
+ pic->height = 0;
+ return;
+ }
+ }
+}
+
/*
===============
Draw_Init
R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap);
}
+extern cvar_t gl_mesh_drawmode;
void R_DrawQueue(void)
{
int pos, num, chartexnum, overbright;
char *str, *currentpic;
int batch, batchcount, additive;
unsigned int color;
+ drawqueuemesh_t *mesh;
if (!r_render.integer)
return;
x += w;
}
break;
+ case DRAWQUEUE_MESH:
+ if (batch)
+ {
+ batch = false;
+ qglEnd();
+ }
+ mesh = (void *)(dq + 1);
+ qglBindTexture(GL_TEXTURE_2D, R_GetTexture(mesh->texture));
+ if (gl_mesh_drawmode.integer > 0)
+ {
+ qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), mesh->vertices);CHECKGLERROR
+ qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), mesh->texcoords);CHECKGLERROR
+ qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(qbyte[4]), mesh->colors);CHECKGLERROR
+ qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
+ qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
+ qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
+ }
+ if (gl_mesh_drawmode.integer == 3 && qglDrawRangeElements == NULL)
+ Cvar_SetValueQuick(&gl_mesh_drawmode, 2);
+
+ if (gl_mesh_drawmode.integer == 3)
+ {
+ // GL 1.2 or GL 1.1 with extension
+ qglDrawRangeElements(GL_TRIANGLES, 0, mesh->numvertices, mesh->numindices, GL_UNSIGNED_INT, mesh->indices);
+ CHECKGLERROR
+ }
+ else if (gl_mesh_drawmode.integer == 2)
+ {
+ // GL 1.1
+ qglDrawElements(GL_TRIANGLES, mesh->numindices, GL_UNSIGNED_INT, mesh->indices);
+ CHECKGLERROR
+ }
+ else if (gl_mesh_drawmode.integer == 1)
+ {
+ int i;
+ // GL 1.1
+ // feed it manually using glArrayElement
+ qglBegin(GL_TRIANGLES);
+ for (i = 0;i < mesh->numindices;i++)
+ qglArrayElement(mesh->indices[i]);
+ qglEnd();
+ CHECKGLERROR
+ }
+ else
+ {
+ int i, in;
+ // GL 1.1 but not using vertex arrays - 3dfx glquake minigl driver
+ // feed it manually
+ if (gl_mesh_drawmode.integer != 0)
+ Cvar_SetValueQuick(&gl_mesh_drawmode, 0);
+ qglBegin(GL_TRIANGLES);
+ for (i = 0;i < mesh->numindices;i++)
+ {
+ in = mesh->indices[i];
+ qglColor4ub(mesh->colors[in * 4], mesh->colors[in * 4 + 1], mesh->colors[in * 4 + 2], mesh->colors[in * 4 + 3]);
+ qglTexCoord2f(mesh->texcoords[in * 2], mesh->texcoords[in * 2 + 1]);
+ qglVertex3f(mesh->vertices[in * 3], mesh->vertices[in * 3 + 1], mesh->vertices[in * 3 + 2]);
+ }
+ qglEnd();
+ CHECKGLERROR
+ }
+ if (gl_mesh_drawmode.integer > 0)
+ {
+ qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
+ qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
+ qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
+ }
+ // restore color, since it got trashed by using color array
+ qglColor4ub((qbyte)(((color >> 24) & 0xFF) >> overbright), (qbyte)(((color >> 16) & 0xFF) >> overbright), (qbyte)(((color >> 8) & 0xFF) >> overbright), (qbyte)(color & 0xFF));
+ CHECKGLERROR
+ currentpic = "\0";
+ break;
}
}
if (batch)
return glt->image->texnum;
}
-static void R_FreeTexture(gltexture_t *glt)
+void R_FreeTexture(rtexture_t *rt)
{
- gltexture_t **gltpointer;
+ gltexture_t *glt, **gltpointer;
gltextureimage_t *image, **gltimagepointer;
GLuint texnum;
+ glt = (gltexture_t *)rt;
if (glt == NULL)
Host_Error("R_FreeTexture: texture == NULL\n");
else
Host_Error("R_FreeTexturePool: pool not linked\n");
while (pool->gltchain)
- R_FreeTexture(pool->gltchain);
+ R_FreeTexture((rtexture_t *)pool->gltchain);
if (pool->imagechain)
Sys_Error("R_FreeTexturePool: not all images freed\n");
Mem_Free(pool);
return (rtexture_t *)glt; // exact match, use existing
}
Con_Printf("R_LoadTexture: cache mismatch on %s, replacing old texture\n", identifier);
- R_FreeTexture(glt);
+ R_FreeTexture((rtexture_t *)glt);
}
return (rtexture_t *)R_SetupTexture(pool, identifier, crc, width, height, flags | GLTEXF_UPLOAD, texinfo, data, NULL, NULL, 0);
return (rtexture_t *)glt; // exact match, use existing
}
Con_Printf("R_LoadTexture: cache mismatch, replacing old texture\n");
- R_FreeTexture(glt);
+ R_FreeTexture((rtexture_t *)glt);
}
return (rtexture_t *)R_SetupTexture(pool, identifier, 0, width, height, flags | GLTEXF_PROCEDURAL | GLTEXF_UPLOAD, texinfo, NULL, generate, proceduraldata, proceduraldatasize);
*/
// host.c -- coordinates spawning and killing of local servers
-#include "quakedef.h"
#include <time.h>
+#include "quakedef.h"
+#include "cl_video.h"
/*
ui_update();
+ CL_VideoFrame();
+
// update video
if (host_speeds.integer)
time1 = Sys_DoubleTime ();
#if you want no CD audio
CD=cd_null.o
-OBJECTS= builddate.o $(CD) $(SND) chase.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_tent.o cmd.o common.o console.o crc.o cvar.o fractalnoise.o gl_draw.o r_sky.o gl_rmain.o gl_rsurf.o host.o host_cmd.o image.o keys.o mathlib.o menu.o model_alias.o model_brush.o model_shared.o model_sprite.o net_bsd.o net_udp.o net_dgrm.o net_loop.o net_main.o pr_cmds.o pr_edict.o pr_exec.o r_light.o r_explosion.o sbar.o sv_main.o sv_move.o sv_phys.o sv_user.o sv_light.o sys_linux.o transform.o view.o wad.o world.o zone.o vid_shared.o palette.o r_crosshairs.o gl_textures.o gl_models.o r_sprites.o r_modules.o r_explosion.o r_lerpanim.o protocol.o quakeio.o r_clip.o ui.o portals.o sys_shared.o cl_light.o gl_backend.o cl_particles.o cl_screen.o cgamevm.o cgame.o filematch.o collision.o cl_collision.o matrixlib.o
+OBJECTS= builddate.o $(CD) $(SND) chase.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_tent.o cmd.o common.o console.o crc.o cvar.o fractalnoise.o gl_draw.o r_sky.o gl_rmain.o gl_rsurf.o host.o host_cmd.o image.o keys.o mathlib.o menu.o model_alias.o model_brush.o model_shared.o model_sprite.o net_bsd.o net_udp.o net_dgrm.o net_loop.o net_main.o pr_cmds.o pr_edict.o pr_exec.o r_light.o r_explosion.o sbar.o sv_main.o sv_move.o sv_phys.o sv_user.o sv_light.o sys_linux.o transform.o view.o wad.o world.o zone.o vid_shared.o palette.o r_crosshairs.o gl_textures.o gl_models.o r_sprites.o r_modules.o r_explosion.o r_lerpanim.o protocol.o quakeio.o r_clip.o ui.o portals.o sys_shared.o cl_light.o gl_backend.o cl_particles.o cl_screen.o cgamevm.o cgame.o filematch.o collision.o cl_collision.o matrixlib.o cl_video.o dpvsimpledecode.o wavefile.o
#K6/athlon optimizations
CPUOPTIMIZATIONS=-march=k6
-OBJECTS= builddate.o chase.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_tent.o cmd.o common.o console.o crc.o cvar.o fractalnoise.o gl_draw.o r_sky.o gl_rmain.o gl_rsurf.o host.o host_cmd.o image.o keys.o mathlib.o menu.o model_alias.o model_brush.o model_shared.o model_sprite.o net_dgrm.o net_loop.o net_main.o pr_cmds.o pr_edict.o pr_exec.o r_light.o r_explosion.o sbar.o snd_dma.o snd_mem.o snd_mix.o sv_main.o sv_move.o sv_phys.o sv_user.o sv_light.o transform.o view.o wad.o world.o zone.o vid_shared.o palette.o r_crosshairs.o gl_textures.o gl_models.o r_sprites.o r_modules.o r_explosion.o r_lerpanim.o protocol.o quakeio.o r_clip.o ui.o portals.o sys_shared.o cl_light.o gl_backend.o cl_particles.o cl_screen.o cgamevm.o cgame.o filematch.o collision.o cl_collision.o matrixlib.o
+OBJECTS= builddate.o chase.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_tent.o cmd.o common.o console.o crc.o cvar.o fractalnoise.o gl_draw.o r_sky.o gl_rmain.o gl_rsurf.o host.o host_cmd.o image.o keys.o mathlib.o menu.o model_alias.o model_brush.o model_shared.o model_sprite.o net_dgrm.o net_loop.o net_main.o pr_cmds.o pr_edict.o pr_exec.o r_light.o r_explosion.o sbar.o snd_dma.o snd_mem.o snd_mix.o sv_main.o sv_move.o sv_phys.o sv_user.o sv_light.o transform.o view.o wad.o world.o zone.o vid_shared.o palette.o r_crosshairs.o gl_textures.o gl_models.o r_sprites.o r_modules.o r_explosion.o r_lerpanim.o protocol.o quakeio.o r_clip.o ui.o portals.o sys_shared.o cl_light.o gl_backend.o cl_particles.o cl_screen.o cgamevm.o cgame.o filematch.o collision.o cl_collision.o matrixlib.o cl_video.o dpvsimpledecode.o wavefile.o
#K6/athlon optimizations
#CPUOPTIMIZATIONS=-march=k6
}
-void M_DrawPicTranslate (float cx, float cy, char *picname)
-{
- DrawQ_PicTranslate (menu_x + cx, menu_y + cy, picname, translationTable);
-}
-
-
void M_DrawTextBox (float x, float y, float width, float height)
{
int n;
setup_bottom = setup_oldbottom = cl_color.integer & 15;
}
+// LordHavoc: rewrote this code greatly
+void M_MenuPlayerTranslate (qbyte *translation)
+{
+ int i, c;
+ unsigned int trans[4096];
+ qpic_t *p;
+
+ p = W_GetLumpName ("gfx/menuplyr.lmp");
+ if (!p)
+ return;
+ c = p->width * p->height;
+ if (c > 4096)
+ {
+ Con_Printf("M_MenuPlayerTranslate: image larger than 4096 pixel buffer\n");
+ return;
+ }
+
+ for (i = 0;i < c;i++)
+ trans[i] = d_8to24table[translation[((qbyte *)p->data)[i]]];
+
+ Draw_NewPic("gfx/menuplyr.lmp", p->width, p->height, true, (qbyte *)trans);
+}
void M_Setup_Draw (void)
{
M_Print (72, 140, "Accept Changes");
M_DrawPic (160, 64, "gfx/bigbox.lmp");
- M_BuildTranslationTable(setup_top*16, setup_bottom*16);
- M_DrawPicTranslate (172, 72, "gfx/menuplyr.lmp");
+
+ // LordHavoc: rewrote this code greatly
+ M_BuildTranslationTable (setup_top*16, setup_bottom*16);
+ M_MenuPlayerTranslate (translationTable);
+ M_DrawPic (172, 72, "gfx/menuplyr.lmp");
M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1));
// a procedurally generated texture, often animated over time, note: generate can be NULL (for odd uses)
rtexture_t *R_ProceduralTexture (rtexturepool_t *rtexturepool, char *identifier, int width, int height, int textype, int flags, int (*generate)(qbyte *buffer, int width, int height, void *parameterdata, int parameterdatasize), void *parameterdata, int parameterdatasize);
+// free a texture
+void R_FreeTexture(rtexture_t *rt);
+
// update the image data of a texture, used by lightmap updates and procedural
// textures.
void R_UpdateTexture(rtexture_t *rt, qbyte *data);
if (l < length)
{
memset(samples + l * 2, 0, (length - l) * sizeof(int[2]));
- //Con_Printf("S_RawSamples_Dequeue: padding with %i\n", length - l);
+ //Con_Printf("S_RawSamples_Dequeue: padding with %i samples\n", length - l);
}
s_rawsamplesbuffer_start = (s_rawsamplesbuffer_start + l) % RAWSAMPLESBUFFER;
s_rawsamplesbuffer_count -= l;
s_rawsamplesbuffer_start = 0;
}
+int S_RawSamples_QueueWantsMore(void)
+{
+ if (s_rawsamplesbuffer_count < min(shm->speed >> 1, RAWSAMPLESBUFFER >> 1))
+ return RAWSAMPLESBUFFER - s_rawsamplesbuffer_count;
+ else
+ return 0;
+}
+
+void S_ResampleBuffer16Stereo(short *input, int inputlength, short *output, int outputlength)
+{
+ if (inputlength != outputlength)
+ {
+ int i, position, stopposition, step;
+ short *in, *out;
+ step = (float) inputlength * 256.0f / (float) outputlength;
+ position = 0;
+ stopposition = (inputlength - 1) << 8;
+ out = output;
+ for (i = 0;i < outputlength && position < stopposition;i++, position += step)
+ {
+ in = input + ((position >> 8) << 1);
+ out[0] = (((in[1] - in[0]) * (position & 255)) >> 8) + in[0];
+ out[1] = (((in[3] - in[2]) * (position & 255)) >> 8) + in[2];
+ out += 2;
+ }
+ stopposition = inputlength << 8;
+ for (i = 0;i < outputlength && position < stopposition;i++, position += step)
+ {
+ in = input + ((position >> 8) << 1);
+ out[0] = in[0];
+ out[1] = in[2];
+ out += 2;
+ }
+ }
+ else
+ memcpy(output, input, inputlength * sizeof(short[2]));
+}
void S_RawSamples_Dequeue(int *samples, unsigned int length);
// empty the rawsamples queue
void S_RawSamples_ClearQueue(void);
+// returns how much more data the queue wants, or 0 if it is already full enough
+int S_RawSamples_QueueWantsMore(void);
+
+// resamples one sound buffer into another, while changing the length
+void S_ResampleBuffer16Stereo(short *input, int inputlength, short *output, int outputlength);
#endif
--- /dev/null
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "wavefile.h"
+
+wavefile_t *waveopen(char *filename, char **errorstring)
+{
+ int validfmt, position, length, l;
+ char *error;
+ wavefile_t *w;
+ FILE *file;
+ unsigned char buffer[1024];
+ error = NULL;
+ file = fopen(filename, "rb");
+ if (file)
+ {
+ w = malloc(sizeof(*w));
+ memset(w, 0, sizeof(*w));
+ if (w)
+ {
+ w->file = file;
+ if (fread(buffer, 12, 1, w->file))
+ {
+ if (!memcmp(buffer, "RIFF", 4))
+ {
+ if (!memcmp(buffer + 8, "WAVE", 4))
+ {
+ validfmt = 0;
+ for(;;)
+ {
+ if (!fread(buffer, 8, 1, w->file))
+ {
+ //error = "error reading chunk\n");
+ break;
+ }
+ position = ftell(w->file);
+ length = buffer[4] | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24);
+ if (!memcmp(buffer, "fmt ", 4))
+ {
+ validfmt = 0;
+ l = length;
+ if (l > 16)
+ l = 16;
+ if (!fread(buffer, l, 1, w->file))
+ {
+ error = "error reading \"fmt \" chunk\n";
+ break;
+ }
+ w->info_format = buffer[0] | (buffer[1] << 8);
+ if (w->info_format != 1)
+ {
+ error = "only PCM format supported\n";
+ break;
+ }
+ w->info_channels = buffer[2] | (buffer[3] << 8);
+ if (w->info_channels != 1 && w->info_channels != 2)
+ {
+ error = "only mono and stereo supported\n";
+ break;
+ }
+ w->info_rate = buffer[4] | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24);
+ if (w->info_rate < 1)
+ {
+ error = "only rates 1hz-100khz supported\n";
+ break;
+ }
+ w->info_bits = buffer[14] | (buffer[15] << 8);
+ if (w->info_bits != 8 && w->info_bits != 16)
+ {
+ error = "only 8bit and 16bit supported\n";
+ break;
+ }
+ validfmt = 1;
+ }
+ else if (!memcmp(buffer, "data", 4))
+ {
+ if (validfmt)
+ {
+ w->datalength = length;
+ w->dataposition = position;
+ }
+ }
+ // other chunks that might be of interest:
+ // "cue " (for looping)
+ if (fseek(w->file, position + length, SEEK_SET))
+ {
+ error = "error seeking to next chunk\n";
+ break;
+ }
+ }
+ if (w->datalength && validfmt)
+ {
+ w->info_bytesperchannel = w->info_bits / 8;
+ w->info_bytespersample = w->info_channels * w->info_bytesperchannel;
+ w->length = w->datalength / w->info_bytespersample;
+ w->position = 0;
+ fseek(w->file, w->dataposition, SEEK_SET);
+ return w;
+ }
+ }
+ else
+ error = "not a RIFF WAVE file\n";
+ }
+ else
+ error = "not a RIFF file\n";
+ }
+ else
+ error = "error reading file\n";
+ free(w);
+ }
+ else
+ error = "unable to allocate memory\n";
+ fclose(file);
+ }
+ else
+ error = "unable to open file\n";
+ if (errorstring)
+ *errorstring = error;
+ return NULL;
+}
+
+void waveclose(wavefile_t *f)
+{
+ if (f)
+ {
+ fclose(f->file);
+ free(f);
+ }
+}
+
+unsigned int waveread16stereo(wavefile_t *w, short *soundbuffer, unsigned int samples)
+{
+ int i;
+ int length;
+ unsigned char *in;
+ short *out;
+ length = samples;
+ if (length > w->length - w->position)
+ length = w->length - w->position;
+ if (w->bufferlength < length)
+ {
+ if (w->buffer)
+ free(w->buffer);
+ w->bufferlength = length + 100;
+ w->buffer = malloc(w->bufferlength * w->info_bytespersample);
+ }
+ length = fread(w->buffer, w->info_bytespersample, length, w->file);
+ w->position += length;
+ if (length > 0)
+ {
+ if (w->info_bytesperchannel == 2)
+ {
+ if (w->info_channels == 2)
+ {
+ for (i = 0, in = w->buffer, out = soundbuffer;i < length;i++, in += 4, out += 2)
+ {
+ out[0] = in[0] | (in[1] << 8);
+ out[1] = in[2] | (in[3] << 8);
+ }
+ }
+ else
+ for (i = 0, in = w->buffer, out = soundbuffer;i < length;i++, in += 2, out += 2)
+ out[0] = out[1] = in[0] | (in[1] << 8);
+ }
+ else
+ {
+ if (w->info_channels == 2)
+ {
+ for (i = 0, in = w->buffer, out = soundbuffer;i < length;i++, in += 2, out += 2)
+ {
+ out[0] = (in[0] - 128) << 8;
+ out[1] = (in[1] - 128) << 8;
+ }
+ }
+ else
+ for (i = 0, in = w->buffer, out = soundbuffer;i < length;i++, in += 1, out += 2)
+ out[0] = out[1] = (in[0] - 128) << 8;
+ }
+ }
+ return length;
+}
+
+unsigned int waveseek(wavefile_t *w, unsigned int samples)
+{
+ if (samples > w->datalength)
+ return 1;
+ else
+ {
+ w->position = samples;
+ fseek(w->file, w->dataposition + w->position * w->info_bytespersample, SEEK_SET);
+ return 0;
+ }
+}
--- /dev/null
+
+#ifndef WAVEFILE_H
+#define WAVEFILE_H
+
+typedef struct wavefile_s
+{
+ // file this is reading from
+ FILE *file;
+
+ // these settings are read directly from the wave format
+ // 1 is uncompressed PCM
+ unsigned int info_format;
+ // how many samples per second
+ unsigned int info_rate;
+ // how many channels (1 = mono, 2 = stereo, 6 = 5.1 audio?)
+ unsigned int info_channels;
+ // how many bits per channel (8 or 16)
+ unsigned int info_bits;
+
+ // these settings are generated from the wave format
+ // how many bytes in a sample (which may be one or two channels, thus 1 or 2 or 2 or 4, depending on info_bytesperchannel)
+ unsigned int info_bytespersample;
+ // how many bytes in channel (1 for 8bit, or 2 for 16bit)
+ unsigned int info_bytesperchannel;
+
+ // how many samples in the wave file
+ unsigned int length;
+
+ // how large the data chunk is
+ unsigned int datalength;
+ // beginning of data in data chunk
+ unsigned int dataposition;
+
+ // current position in stream (in samples)
+ unsigned int position;
+
+ // these are private to the wave file functions, just used for processing
+ // size of *buffer
+ unsigned int bufferlength;
+ // buffer is reallocated if caller asks for more than fits
+ void *buffer;
+
+}
+wavefile_t;
+
+// opens a wave file, if an error occurs and errorstring is not NULL,
+// *errorstring will be set to a message describing the error
+wavefile_t *waveopen(char *filename, char **errorstring);
+// closes a wave file
+void waveclose(wavefile_t *f);
+
+// reads some data from the file as 16bit stereo (converting if necessary)
+// returns number of samples read (may be less than requested)
+// if not all samples could be read, the remaining buffer will be unmodified
+unsigned int waveread16stereo(wavefile_t *f, short *soundbuffer, unsigned int samples);
+
+// seeks to a desired position in the wave
+// returns 0 if successful, 1 if not successful
+unsigned int waveseek(wavefile_t *f, unsigned int samples);
+
+#endif