add geometry shader support. because why not.

bind command now makes it a bit easier to edit the binding. and any alias.
autoid tweaks.
slightly better q1qvm/ktx support. extend the api a little.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4927 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-07-01 23:15:25 +00:00
parent 6515417cd6
commit 667e8dec10
26 changed files with 1408 additions and 795 deletions

View File

@ -896,10 +896,11 @@ void CL_PredictMovePNum (int seat)
pv->nolocalplayer = !!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || (cls.protocol != CP_QUAKEWORLD);
if (!cl.spectator) //just in case
if (!cl.spectator && (pv->cam_state != CAM_FREECAM || pv->cam_spec_track != -1)) //just in case
{
pv->cam_state = CAM_FREECAM;
pv->cam_spec_track = -1;
pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1);
}
#ifdef Q2CLIENT

View File

@ -2279,6 +2279,7 @@ static void Image_LoadTexture_Failed(void *ctx, void *data, size_t a, size_t b)
}
static void Image_LoadTextureMips(void *ctx, void *data, size_t a, size_t b)
{
int i;
texid_t tex = ctx;
struct pendingtextureinfo *mips = data;
@ -2288,6 +2289,12 @@ static void Image_LoadTextureMips(void *ctx, void *data, size_t a, size_t b)
tex->status = TEX_LOADED;
else
tex->status = TEX_FAILED;
for (i = 0; i < mips->mipcount; i++)
if (mips->mip[i].needfree)
BZ_Free(mips->mip[i].data);
if (mips->extrafree)
BZ_Free(mips->extrafree);
BZ_Free(mips);
if (!strncmp(tex->ident, "gfx/", 4))

View File

@ -601,6 +601,15 @@ void Key_ConsoleInsert(char *instext)
}
key_linepos += len;
}
void Key_ConsoleReplace(char *instext)
{
if (!*instext)
return;
key_linepos = 1;
key_lines[edit_line][key_linepos] = 0;
Key_ConsoleInsert(instext);
}
void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
{
@ -792,6 +801,12 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
Cbuf_AddText(va("\nmap %s\n", c), RESTRICT_LOCAL);
return;
}
c = Info_ValueForKey(info, "type");
if (*c)
{
Key_ConsoleReplace(c);
return;
}
c = Info_ValueForKey(info, "cmd");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
@ -1716,6 +1731,18 @@ void Key_Unbindall_f (void)
Key_SetBinding (i, ~0, NULL, Cmd_ExecLevel);
}
void Key_AliasEdit_f (void)
{
char *alias = Cmd_AliasExist(Cmd_Argv(1), RESTRICT_LOCAL);
char quotedalias[2048];
if (alias)
{
COM_QuotedString(alias, quotedalias, sizeof(quotedalias), false);
Key_ConsoleReplace(va("alias %s %s", Cmd_Argv(1), quotedalias));
}
else
Con_Printf("Not an alias\n");
}
/*
===================
@ -1747,7 +1774,19 @@ void Key_Bind_f (void)
if (modifier == ~0) //modifier unspecified. default to no modifier
modifier = 0;
if (keybindings[b][modifier])
Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b][modifier] );
{
char *alias = Cmd_AliasExist(keybindings[b][modifier], RESTRICT_LOCAL);
char quotedbind[2048];
char quotedalias[2048];
COM_QuotedString(keybindings[b][modifier], quotedbind, sizeof(quotedbind), false);
if (alias)
{
COM_QuotedString(alias, quotedalias, sizeof(quotedalias), false);
Con_Printf ("^[\"%s\"\\type\\bind %s %s^] = ^[\"%s\"\\type\\alias %s %s^]\n", Cmd_Argv(1), Cmd_Argv(1), quotedbind, keybindings[b][modifier], keybindings[b][modifier], quotedalias);
}
else
Con_Printf ("^[\"%s\"\\type\\bind %s %s^] = \"%s\"\n", Cmd_Argv(1), keybindings[b][modifier], Cmd_Argv(1), keybindings[b][modifier] );
}
else
Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
return;
@ -1976,6 +2015,7 @@ void Key_Init (void)
Cmd_AddCommand ("bindlevel",Key_BindLevel_f);
Cmd_AddCommand ("unbind",Key_Unbind_f);
Cmd_AddCommand ("unbindall",Key_Unbindall_f);
Cmd_AddCommand ("aliasedit",Key_AliasEdit_f);
Cvar_Register (&con_selectioncolour, "Console variables");
Cvar_Register (&con_echochat, "Console variables");

View File

@ -1537,6 +1537,7 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
float barwidth;
qboolean haveinfo;
unsigned int textflags;
int h;
static vec4_t healthcolours[] =
{
@ -1614,6 +1615,8 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
if (!haveinfo)
return; //we don't trust the info that we have, so no ids.
h = 0;
//display health bar
if (scr_autoid_health.ival)
{
@ -1627,6 +1630,7 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
health = 100;
}
barwidth = 32;
h += 8;
y -= 8;
R2D_ImageColours(healthcolours[r][0], healthcolours[r][1], healthcolours[r][2], healthcolours[r][3]*alpha);
R2D_FillBlock(x - barwidth*0.5 + barwidth * health/100.0, y, barwidth * (100-health)/100.0, 8);
@ -1647,6 +1651,7 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
else r = -1;
if (r >= 0)
{
h += 8;
y -= 8;
armour = bound(0, armour, health);
barwidth = 32;
@ -1660,10 +1665,9 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
if (scr_autoid_weapon.ival)
{
if (scr_autoid_armour.ival && scr_autoid_health.ival)
y += 4;
else if (!scr_autoid_armour.ival && !scr_autoid_health.ival)
y -= 8;
if (h < 8)
h = 8;
y += (h-8)/2;
for (r = 7; r>=0; r--)
if (items & (1<<r))
@ -1672,7 +1676,19 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
if (r >= 0)
{
len = COM_ParseFunString(textflags, wbitnames[r]->string, buffer, sizeof(buffer), false) - buffer;
Draw_ExpandedString(x + barwidth*0.5 + 4, y, buffer);
if (textflags & CON_HALFALPHA)
{
for (r = 0; r < len; r++)
if (!(buffer[r] & CON_RICHFORECOLOUR))
buffer[r] |= CON_HALFALPHA;
}
if (len && (buffer[0] & CON_CHARMASK) == '{' && (buffer[len-1] & CON_CHARMASK) == '}')
{ //these are often surrounded by {} to make them white in chat messages, and recoloured.
buffer[len-1] = 0;
Draw_ExpandedString(x + barwidth*0.5 + 4, y, buffer+1);
}
else
Draw_ExpandedString(x + barwidth*0.5 + 4, y, buffer);
}
}
}

View File

@ -2165,6 +2165,8 @@ void Cmd_ExecuteString (char *text, int level)
Cmd_ExpandStringArguments (a->value, dest, sizeof(dest));
Cbuf_InsertText (dest, execlevel, false);
Con_DPrintf("Execing alias %s:\n%s\n", a->name, a->value);
return;
}
}
@ -2806,7 +2808,7 @@ void Cmd_set_f(void)
if (Cmd_Argc()<3)
{
Con_TPrintf("set <var> <equation>\n");
Con_TPrintf("%s %s <equation>\n", Cmd_Argv(0), *Cmd_Argv(1)?Cmd_Argv(1):"<var>");
return;
}

View File

@ -3962,7 +3962,7 @@ static void PR_uri_get_callback(struct dl_download *dl)
int selfnum = dl->user_num;
func_t func;
if (!prinst)
if (!prinst || dl->user_sequence != svs.spawncount)
return;
func = PR_FindFunction(prinst, "URI_Get_Callback", PR_ANY);
@ -4048,6 +4048,7 @@ void QCBUILTIN PF_uri_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
dl->user_ctx = w;
dl->user_float = id;
dl->user_num = *w->g.self;
dl->user_sequence = svs.spawncount;
dl->isquery = true;
G_FLOAT(OFS_RETURN) = 1;
}

View File

@ -483,11 +483,11 @@ void QCBUILTIN PF_setspawnparms (pubprogfuncs_t *prinst, struct globalvars_s *pr
void QCBUILTIN PF_precache_vwep_model(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *value);
int PF_checkclient_Internal (pubprogfuncs_t *prinst);
void PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s);
int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s);
int PF_precache_model_Internal (pubprogfuncs_t *prinst, const char *s, qboolean queryonly);
void PF_setmodel_Internal (pubprogfuncs_t *prinst, edict_t *e, const char *m);
char *PF_infokey_Internal (int entnum, const char *value);
void PF_stuffcmd_Internal(int entnum, const char *str);
void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags);
void PF_centerprint_Internal (int entnum, qboolean plaque, const char *s);
void PF_WriteString_Internal (int target, const char *str);
pbool QDECL ED_CanFree (edict_t *ed);

View File

@ -99,12 +99,29 @@ dllhandle_t *QVM_LoadDLL(const char *name, qboolean binroot, void **vmMain, sys_
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
// run through the search paths
iterator = NULL;
while (!hVM && COM_IteratePaths(&iterator, NULL, 0, gpath, sizeof(gpath)))
{
if (!hVM && FS_NativePath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
{
Con_DPrintf("Loading native: %s\n", fname);
hVM = Sys_LoadLibrary(fname, funcs);
}
if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
{
Con_DPrintf("Loading native: %s\n", fname);
hVM = Sys_LoadLibrary(fname, funcs);
}
}
}
else
{
// run through the search paths
iterator = NULL;
while (!hVM && COM_IteratePaths(&iterator, gpath, sizeof(gpath), NULL, false))
while (!hVM && COM_IteratePaths(&iterator, gpath, sizeof(gpath), NULL, 0))
{
if (!hVM)
{

View File

@ -1893,12 +1893,14 @@ static void BE_ApplyUniforms(program_t *prog, int permu)
ID3D11DeviceContext_VSSetShader(d3ddevctx, prog->permu[permu].handle.hlsl.vert, NULL, 0);
ID3D11DeviceContext_HSSetShader(d3ddevctx, prog->permu[permu].handle.hlsl.hull, NULL, 0);
ID3D11DeviceContext_DSSetShader(d3ddevctx, prog->permu[permu].handle.hlsl.domain, NULL, 0);
ID3D11DeviceContext_GSSetShader(d3ddevctx, prog->permu[permu].handle.hlsl.geom, NULL, 0);
ID3D11DeviceContext_PSSetShader(d3ddevctx, prog->permu[permu].handle.hlsl.frag, NULL, 0);
ID3D11DeviceContext_IASetPrimitiveTopology(d3ddevctx, prog->permu[permu].handle.hlsl.topology);
ID3D11DeviceContext_VSSetConstantBuffers(d3ddevctx, 0, 3, cbuf);
ID3D11DeviceContext_HSSetConstantBuffers(d3ddevctx, 0, 3, cbuf);
ID3D11DeviceContext_DSSetConstantBuffers(d3ddevctx, 0, 3, cbuf);
ID3D11DeviceContext_GSSetConstantBuffers(d3ddevctx, 0, 3, cbuf);
ID3D11DeviceContext_PSSetConstantBuffers(d3ddevctx, 0, 3, cbuf);
}

View File

@ -246,14 +246,6 @@ qboolean D3D11_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips)
D3D11_DestroyTexture(tex);
hr = ID3D11Device_CreateTexture2D(pD3DDev11, &tdesc, (mips->mip[0].data?subresdesc:NULL), (ID3D11Texture2D**)&tex->ptr);
for (i = 0; i < mips->mipcount; i++)
{
if (mips->mip[i].needfree)
BZ_Free(mips->mip[i].data);
}
if (mips->extrafree)
BZ_Free(mips->extrafree);
return !FAILED(hr);
}
void D3D11_UploadLightmap(lightmapinfo_t *lm)

View File

@ -236,6 +236,7 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int
void *vblob, size_t vsize,
void *hblob, size_t hsize,
void *dblob, size_t dsize,
void *gblob, size_t gsize,
void *fblob, size_t fsize)
{
qboolean success = true;
@ -255,6 +256,9 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int
else
prog->permu[permu].handle.hlsl.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
if (gblob && FAILED(ID3D11Device_CreateGeometryShader(pD3DDev11, gblob, gsize, NULL, (ID3D11GeometryShader**)&prog->permu[permu].handle.hlsl.geom)))
success = false;
if (FAILED(ID3D11Device_CreatePixelShader(pD3DDev11, fblob, fsize, NULL, (ID3D11PixelShader**)&prog->permu[permu].handle.hlsl.frag)))
success = false;
@ -358,8 +362,8 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int
static qboolean D3D11Shader_LoadBlob(program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile)
{
qboolean success;
char *vblob, *hblob, *dblob, *fblob;
unsigned int vsz, hsz, dsz, fsz;
char *vblob, *hblob, *dblob, *gblob, *fblob;
unsigned int vsz, hsz, dsz, gsz, fsz;
VFS_READ(blobfile, &vsz, sizeof(vsz));
vblob = Z_Malloc(vsz);
@ -383,20 +387,30 @@ static qboolean D3D11Shader_LoadBlob(program_t *prog, const char *name, unsigned
else
dblob = NULL;
VFS_READ(blobfile, &gsz, sizeof(gsz));
if (dsz != ~0u)
{
gblob = Z_Malloc(gsz);
VFS_READ(blobfile, gblob, gsz);
}
else
gblob = NULL;
VFS_READ(blobfile, &fsz, sizeof(fsz));
fblob = Z_Malloc(fsz);
VFS_READ(blobfile, fblob, fsz);
success = D3D11Shader_CreateShaders(prog, name, permu, vblob, vsz, hblob, hsz, dblob, dsz, fblob, fsz);
success = D3D11Shader_CreateShaders(prog, name, permu, vblob, vsz, hblob, hsz, dblob, dsz, gblob, gsz, fblob, fsz);
Z_Free(vblob);
Z_Free(hblob);
Z_Free(dblob);
Z_Free(gblob);
Z_Free(fblob);
return success;
}
qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *hull, const char *domain, const char *frag, qboolean silenterrors, vfsfile_t *blobfile)
qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *hull, const char *domain, const char *geom, const char *frag, qboolean silenterrors, vfsfile_t *blobfile)
{
static const char *defaultsamplers[] =
{
@ -427,8 +441,9 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
char *hsformat = NULL;
char *dsformat = NULL;
char *fsformat;
char *gsformat = NULL;
D3D_SHADER_MACRO defines[64];
ID3DBlob *vcode = NULL, *hcode = NULL, *dcode = NULL, *fcode = NULL, *errors = NULL;
ID3DBlob *vcode = NULL, *hcode = NULL, *dcode = NULL, *gcode = NULL, *fcode = NULL, *errors = NULL;
qboolean success = false;
ID3D11ShaderReflection *freflect;
int i;
@ -438,16 +453,19 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
vsformat = "vs_5_0";
hsformat = "hs_5_0";
dsformat = "ds_5_0";
gsformat = "gs_5_0";
fsformat = "ps_5_0";
}
else if (d3dfeaturelevel >= D3D_FEATURE_LEVEL_10_1)
{
vsformat = "vs_4_1";
gsformat = "gs_4_1";
fsformat = "ps_4_1";
}
else if (d3dfeaturelevel >= D3D_FEATURE_LEVEL_10_0)
{
vsformat = "vs_4_0";
gsformat = "gs_4_0";
fsformat = "ps_4_0";
}
else if (d3dfeaturelevel >= D3D_FEATURE_LEVEL_9_3)
@ -463,6 +481,9 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
prog->permu[permu].handle.hlsl.vert = NULL;
prog->permu[permu].handle.hlsl.frag = NULL;
prog->permu[permu].handle.hlsl.hull = NULL;
prog->permu[permu].handle.hlsl.domain = NULL;
prog->permu[permu].handle.hlsl.geom = NULL;
prog->permu[permu].handle.hlsl.layout = NULL;
if (pD3DCompile)
@ -547,6 +568,24 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
}
}
if (geom)
{
if (!dsformat)
success = false;
else
{
defines[0].Name = "GEOMETRY_SHADER";
if (FAILED(pD3DCompile(domain, strlen(domain), name, defines, &myd3dinclude, "main", gsformat, 0, 0, &gcode, &errors)))
success = false;
if (errors && !silenterrors)
{
char *messages = ID3DBlob_GetBufferPointer(errors);
Con_Printf("geometry shader %s:\n%s", name, messages);
ID3DBlob_Release(errors);
}
}
}
defines[0].Name = "FRAGMENT_SHADER";
if (FAILED(pD3DCompile(frag, strlen(frag), name, defines, &myd3dinclude, "main", fsformat, 0, 0, &fcode, &errors)))
success = false;
@ -568,6 +607,7 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
ID3DBlob_GetBufferPointer(vcode), ID3DBlob_GetBufferSize(vcode),
hcode?ID3DBlob_GetBufferPointer(hcode):NULL, hcode?ID3DBlob_GetBufferSize(hcode):0,
dcode?ID3DBlob_GetBufferPointer(dcode):NULL, dcode?ID3DBlob_GetBufferSize(dcode):0,
gcode?ID3DBlob_GetBufferPointer(gcode):NULL, gcode?ID3DBlob_GetBufferSize(gcode):0,
ID3DBlob_GetBufferPointer(fcode), ID3DBlob_GetBufferSize(fcode));
if (success && blobfile)
@ -601,6 +641,18 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
VFS_WRITE(blobfile, ID3DBlob_GetBufferPointer(dcode), sz);
}
if (!gcode)
{
sz = ~0u;
VFS_WRITE(blobfile, &sz, sizeof(sz));
}
else
{
sz = ID3DBlob_GetBufferSize(gcode);
VFS_WRITE(blobfile, &sz, sizeof(sz));
VFS_WRITE(blobfile, ID3DBlob_GetBufferPointer(gcode), sz);
}
sz = ID3DBlob_GetBufferSize(fcode);
VFS_WRITE(blobfile, &sz, sizeof(sz));
VFS_WRITE(blobfile, ID3DBlob_GetBufferPointer(fcode), sz);
@ -641,6 +693,8 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
ID3DBlob_Release(hcode);
if (dcode)
ID3DBlob_Release(dcode);
if (gcode)
ID3DBlob_Release(gcode);
if (fcode)
ID3DBlob_Release(fcode);
}

View File

@ -84,6 +84,8 @@ qboolean D3D9_LoadTextureMips(image_t *tex, struct pendingtextureinfo *mips)
return false;
}
if (!pD3DDev9)
return false; //can happen on errors
if (FAILED(IDirect3DDevice9_CreateTexture(pD3DDev9, mips->mip[0].width, mips->mip[0].height, mips->mipcount, 0, fmt, D3DPOOL_MANAGED, &dt, NULL)))
return false;

View File

@ -141,12 +141,18 @@ static dllhandle_t *shaderlib;
(This)->lpVtbl -> Release(This)
#endif
static qboolean D3D9Shader_CreateProgram (program_t *prog, const char *sname, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *frag, qboolean silent, vfsfile_t *blobfile)
static qboolean D3D9Shader_CreateProgram (program_t *prog, const char *sname, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile)
{
D3DXMACRO defines[64];
LPD3DXBUFFER code = NULL, errors = NULL;
qboolean success = false;
if (geom || tcs || tes)
{
Con_Printf("geometry and tessellation shaders are not availale in d3d9 (%s)\n", sname);
return false;
}
prog->permu[permu].handle.hlsl.vert = NULL;
prog->permu[permu].handle.hlsl.frag = NULL;

View File

@ -3508,7 +3508,7 @@ void GLBE_SelectMode(backendmode_t mode)
if (!shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}
/*BEM_DEPTHONLY does support mesh writing, but its not the only way its used... FIXME!*/
@ -3533,7 +3533,7 @@ void GLBE_SelectMode(backendmode_t mode)
if (gl_config_nofixedfunc && !shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}
@ -4058,7 +4058,7 @@ static void DrawMeshes(void)
if (!shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}

View File

@ -376,9 +376,6 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips)
qglTexImage3D(targface, i, GL_RGB, size, size, size, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, mips->mip[i].data);
break;
}
if (mips->mip[i].needfree)
Z_Free(mips->mip[i].data);
}
}
else
@ -466,13 +463,9 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips)
qglCompressedTexImage2DARB(targface, j, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, mips->mip[i].width, mips->mip[i].height, 0, mips->mip[i].datasize, mips->mip[i].data);
break;
}
if (mips->mip[i].needfree)
Z_Free(mips->mip[i].data);
}
}
if (mips->extrafree)
Z_Free(mips->extrafree);
return true;
}

View File

@ -983,6 +983,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
unsigned int permuoffsets[PERMUTATIONS], initoffset=0;
unsigned int blobheaderoffset=0;
qboolean blobadded;
qboolean geom = false;
qboolean tess = false;
char *cvarnames[64];
@ -1014,6 +1015,11 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
prog->nofixedcompat = false;
script += 7;
}
else if (!strncmp(script, "!!geom", 6))
{
geom = true;
script += 6;
}
else if (!strncmp(script, "!!tess", 6))
{
tess = true;
@ -1334,7 +1340,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
initoffset = VFS_GETLEN(blobfile);
VFS_SEEK(blobfile, initoffset);
}
if (!sh_config.pCreateProgram(prog, name, p, ver, permutationdefines, script, tess?script:NULL, tess?script:NULL, script, (p & PERMUTATION_SKELETAL)?true:onefailed, sh_config.pValidateProgram?NULL:blobfile))
if (!sh_config.pCreateProgram(prog, name, p, ver, permutationdefines, script, tess?script:NULL, tess?script:NULL, geom?script:NULL, script, (p & PERMUTATION_SKELETAL)?true:onefailed, sh_config.pValidateProgram?NULL:blobfile))
{
if (!(p & PERMUTATION_SKELETAL))
onefailed = true; //don't flag it if skeletal failed.

View File

@ -1005,6 +1005,11 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
if (GL_CheckExtension("GL_ARB_seamless_cube_map"))
qglEnable(0x884F); //TEXTURE_CUBE_MAP_SEAMLESS 0x884F
if (!gl_config.gles && gl_config.glversion >= 3.2)
gl_config.geometryshaders = true;
else
gl_config.geometryshaders = false;
#ifdef GL_STATIC
gl_config.ext_framebuffer_objects = true; //exists as core in gles2
#else
@ -1773,6 +1778,11 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char *
strings++;
}
break;
case GL_GEOMETRY_SHADER_ARB:
prstrings[strings] = "#define GEOMETRY_SHADER\n";
length[strings] = strlen(prstrings[strings]);
strings++;
break;
case GL_TESS_CONTROL_SHADER_ARB:
prstrings[strings] = "#define TESS_CONTROL_SHADER\n";
length[strings] = strlen(prstrings[strings]);
@ -1976,12 +1986,13 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL
return shader;
}
GLhandleARB GLSlang_CreateProgramObject (const char *name, GLhandleARB vert, GLhandleARB cont, GLhandleARB eval, GLhandleARB frag, qboolean silent)
GLhandleARB GLSlang_CreateProgramObject (const char *name, GLhandleARB vert, GLhandleARB cont, GLhandleARB eval, GLhandleARB geom, GLhandleARB frag, qboolean silent)
{
GLhandleARB program;
program = qglCreateProgramObjectARB();
if (vert) qglAttachObjectARB(program, vert);
if (geom) qglAttachObjectARB(program, geom);
if (cont) qglAttachObjectARB(program, cont);
if (eval) qglAttachObjectARB(program, eval);
if (frag) qglAttachObjectARB(program, frag);
@ -2058,10 +2069,11 @@ qboolean GLSlang_ValidateProgram(union programhandle_u *h, const char *name, qbo
return true;
}
union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const char **precompilerconstants, const char *vert, const char *cont, const char *eval, const char *frag, qboolean silent, vfsfile_t *blobfile)
union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const char **precompilerconstants, const char *vert, const char *cont, const char *eval, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile)
{
union programhandle_u ret;
GLhandleARB vs;
GLhandleARB gs;
GLhandleARB fs;
GLhandleARB cs;
GLhandleARB es;
@ -2073,7 +2085,12 @@ union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const cha
return ret;
if ((cont || eval) && !qglPatchParameteriARB)
{
Con_Printf("GLSlang_CreateProgram: %s requires tesselation support, but your gl drivers do not appear to support this\n", name);
Con_Printf("GLSlang_CreateProgram: %s requires tesselation support, but your gl drivers do not appear to support this (gl4.0 feature)\n", name);
return ret;
}
if (geom && !gl_config.geometryshaders)
{
Con_Printf("GLSlang_CreateProgram: %s requires geometry shader support, but your gl drivers do not appear to support this (gl3.2 feature)\n", name);
return ret;
}
@ -2081,11 +2098,13 @@ union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const cha
precompilerconstants = &nullconstants;
fs = GLSlang_CreateShader(name, ver, precompilerconstants, frag, GL_FRAGMENT_SHADER_ARB, silent);
gs = GLSlang_CreateShader(name, ver, precompilerconstants, geom, GL_GEOMETRY_SHADER_ARB, silent);
vs = GLSlang_CreateShader(name, ver, precompilerconstants, vert, GL_VERTEX_SHADER_ARB, silent);
cs = GLSlang_CreateShader(name, ver, precompilerconstants, cont, GL_TESS_CONTROL_SHADER_ARB, silent);
es = GLSlang_CreateShader(name, ver, precompilerconstants, eval, GL_TESS_EVALUATION_SHADER_ARB, silent);
fs = GLSlang_FinishShader(fs, name, GL_FRAGMENT_SHADER_ARB, silent);
gs = GLSlang_FinishShader(gs, name, GL_GEOMETRY_SHADER_ARB, silent);
vs = GLSlang_FinishShader(vs, name, GL_VERTEX_SHADER_ARB, silent);
cs = GLSlang_FinishShader(cs, name, GL_TESS_CONTROL_SHADER_ARB, silent);
es = GLSlang_FinishShader(es, name, GL_TESS_EVALUATION_SHADER_ARB, silent);
@ -2093,9 +2112,10 @@ union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const cha
if (!vs || !fs)
ret.glsl.handle = 0;
else
ret.glsl.handle = GLSlang_CreateProgramObject(name, vs, cs, es, fs, silent);
ret.glsl.handle = GLSlang_CreateProgramObject(name, vs, cs, es, gs, fs, silent);
//delete ignores 0s.
if (vs) qglDeleteShaderObject_(vs);
if (gs) qglDeleteShaderObject_(gs);
if (fs) qglDeleteShaderObject_(fs);
if (cs) qglDeleteShaderObject_(cs);
if (es) qglDeleteShaderObject_(es);
@ -2132,7 +2152,7 @@ qboolean GLSlang_ValidateProgramPermu(program_t *prog, const char *name, unsigne
{
return GLSlang_ValidateProgram(&prog->permu[permu].handle, name, noerrors, blobfile);
}
qboolean GLSlang_CreateProgramPermu(program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *frag, qboolean noerrors, vfsfile_t *blobfile)
qboolean GLSlang_CreateProgramPermu(program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile)
{
#ifdef FTE_TARGET_WEB
//emscripten's uniform code results in excessive stalls that hinder usability.
@ -2150,7 +2170,7 @@ qboolean GLSlang_CreateProgramPermu(program_t *prog, const char *name, unsigned
ver = 120;
#endif
}
prog->permu[permu].handle = GLSlang_CreateProgram(name, ver, precompilerconstants, vert, tcs, tes, frag, noerrors, blobfile);
prog->permu[permu].handle = GLSlang_CreateProgram(name, ver, precompilerconstants, vert, tcs, tes, geom, frag, noerrors, blobfile);
if (prog->permu[permu].handle.glsl.handle)
return true;
return false;

View File

@ -235,6 +235,8 @@ typedef struct {
qboolean arb_texture_compression;
qboolean geometryshaders;
// qboolean arb_fragment_program;
qboolean arb_shader_objects;
qboolean arb_shadow;
@ -1077,7 +1079,7 @@ extern void (APIENTRY *qglBindVertexArray)(GLuint vaoarray);
//glslang helper api
union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const char **precompilerconstants, const char *vert, const char *cont, const char *eval, const char *frag, qboolean silent, vfsfile_t *blobfile);
union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const char **precompilerconstants, const char *vert, const char *cont, const char *eval, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile);
GLint GLSlang_GetUniformLocation (int prog, char *name);
void GL_SelectProgram(int program);
#define GLSlang_UseProgram(prog) GL_SelectProgram(prog)

View File

@ -586,6 +586,10 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei
#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
#endif
#ifndef GL_GEOMETRY_SHADER_ARB
#define GL_GEOMETRY_SHADER_ARB 0x8DD9
#endif
#ifndef GL_PATCH_VERTICES_ARB //GL_ARB_tessellation_shader lacks _ARB postfix.
#define GL_PATCHES_ARB 0xE
#define GL_PATCH_VERTICES_ARB 0x8E72

View File

@ -443,6 +443,7 @@ union programhandle_u
int topology; //D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
void *hull;
void *domain;
void *geom;
void *layout;
#endif
} hlsl;
@ -674,7 +675,7 @@ typedef struct
void (*pDeleteProg) (program_t *prog, unsigned int permu);
qboolean (*pLoadBlob) (program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile);
qboolean (*pCreateProgram) (program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *frag, qboolean noerrors, vfsfile_t *blobfile);
qboolean (*pCreateProgram) (program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile);
qboolean (*pValidateProgram)(program_t *prog, const char *name, unsigned int permu, qboolean noerrors, vfsfile_t *blobfile);
void (*pProgAutoFields) (program_t *prog, char **cvarnames, int *cvartypes);
} sh_config_t;

View File

@ -103,6 +103,8 @@ struct dl_download
unsigned int user_num;
float user_float;
void *user_ctx;
int user_sequence;
qboolean isquery; //will not be displayed in the download/progress bar stuff.
#ifndef SERVERONLY

View File

@ -3375,7 +3375,7 @@ static void QCBUILTIN PF_checkclient (pubprogfuncs_t *prinst, struct globalvars_
//============================================================================
void PF_stuffcmd_Internal(int entnum, const char *str)
void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags)
{
client_t *cl;
static qboolean expectingcolour;
@ -3468,7 +3468,7 @@ stuffcmd (clientent, value)
*/
static void QCBUILTIN PF_stuffcmd (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
PF_stuffcmd_Internal(G_EDICTNUM(prinst, OFS_PARM0), PR_GetStringOfs(prinst, OFS_PARM1));
PF_stuffcmd_Internal(G_EDICTNUM(prinst, OFS_PARM0), PR_GetStringOfs(prinst, OFS_PARM1), 0);
}
//DP_QC_DROPCLIENT
@ -3700,7 +3700,7 @@ void PR_CheckEmptyString (char *s)
*/
//float(string effectname) particleeffectnum (EXT_CSQC)
static void QCBUILTIN PF_sv_particleeffectnum(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_sv_particleeffectnum(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *s = PR_GetStringOfs(prinst, OFS_PARM0);
/*
@ -3762,14 +3762,14 @@ static void QCBUILTIN PF_precache_file (pubprogfuncs_t *prinst, struct globalvar
FS_FLocateFile(s, FSLFRT_IFFOUND, NULL);
}
void PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
{
int i;
if (s[0] <= ' ')
{
PR_BIError (prinst, "PF_precache_sound: Bad string");
return;
return 0;
}
for (i=1 ; i<MAX_PRECACHE_SOUNDS ; i++)
@ -3793,12 +3793,13 @@ void PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
MSG_WriteString(&sv.nqreliable_datagram, s);
#endif
}
return;
return i;
}
if (!strcmp(sv.strings.sound_precache[i], s))
return;
return i;
}
PR_BIError (prinst, "PF_precache_sound: overflow");
return 0;
}
static void QCBUILTIN PF_precache_sound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -7724,7 +7725,7 @@ static void QCBUILTIN PF_CustomTEnt(pubprogfuncs_t *prinst, struct globalvars_s
}
//void(float effectnum, entity ent, vector start, vector end) trailparticles (EXT_CSQC),
static void QCBUILTIN PF_sv_trailparticles(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_sv_trailparticles(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
#ifdef PEXT_CSQC
int efnum;
@ -7768,7 +7769,7 @@ static void QCBUILTIN PF_sv_trailparticles(pubprogfuncs_t *prinst, struct global
#endif
}
//void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
static void QCBUILTIN PF_sv_pointparticles(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_sv_pointparticles(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
#ifdef PEXT_CSQC
int efnum = G_FLOAT(OFS_PARM0);

File diff suppressed because it is too large Load Diff

View File

@ -668,7 +668,7 @@ void SV_DropClient (client_t *drop)
else if (ISQ3CLIENT(drop))
{
}
if (drop->netchan.remote_address.type != NA_INVALID)
if (drop->netchan.remote_address.type != NA_INVALID && drop->netchan.message.maxsize)
{
//send twice, to cover packetloss a little.
Netchan_Transmit (&drop->netchan, termmsg.cursize, termmsg.data, 10000);
@ -1958,7 +1958,7 @@ client_t *SV_AddSplit(client_t *controller, char *info, int id)
prev->controlled = cl;
prev = cl;
cl->controller = prev->controller?prev->controller:host_client;
cl->controller = controller;
cl->controlled = NULL;
Q_strncpyS (cl->userinfo, info, sizeof(cl->userinfo)-1);

View File

@ -4653,7 +4653,7 @@ void Cmd_Join_f (void)
if (host_client->state != cs_spawned)
return;
if (svs.gametype != GT_PROGS)
if (svs.gametype != GT_PROGS && svs.gametype != GT_Q1QVM)
{
SV_TPrintToClient(host_client, PRINT_HIGH, "Sorry, not implemented in this gamecode type. Try moaning at the dev team\n");
return;
@ -4714,7 +4714,9 @@ void Cmd_Join_f (void)
// call the prog function for removing a client
// this will set the body to a dead frame, among other things
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
if (SpectatorDisconnect)
if (svs.gametype == GT_Q1QVM)
Q1QVM_DropClient(host_client);
else if (SpectatorDisconnect)
PR_ExecuteProgram (svprogfuncs, SpectatorDisconnect);
sv.spawned_observer_slots--;
@ -4727,7 +4729,9 @@ void Cmd_Join_f (void)
// FIXME, bump the client's userid?
// call the progs to get default spawn parms for the new client
if (pr_global_ptrs->SetNewParms)
if (svs.gametype == GT_Q1QVM)
Q1QVM_SetNewParms();
else if (pr_global_ptrs->SetNewParms)
PR_ExecuteProgram (svprogfuncs, pr_global_struct->SetNewParms);
for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
{
@ -4737,15 +4741,20 @@ void Cmd_Join_f (void)
host_client->spawn_parms[i] = 0;
}
// call the spawn function
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientConnect);
if (svs.gametype == GT_Q1QVM)
Q1QVM_ClientConnect(host_client);
else
{
// call the spawn function
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientConnect);
// actually spawn the player
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
PR_ExecuteProgram (svprogfuncs, pr_global_struct->PutClientInServer);
// actually spawn the player
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
PR_ExecuteProgram (svprogfuncs, pr_global_struct->PutClientInServer);
}
sv.spawned_client_slots++;
// send notification to all clients
@ -4781,7 +4790,7 @@ void Cmd_Observe_f (void)
if (host_client->state != cs_spawned)
return;
if (svs.gametype != GT_PROGS)
if (svs.gametype != GT_PROGS && svs.gametype != GT_Q1QVM)
{
SV_TPrintToClient(host_client, PRINT_HIGH, "Sorry, not implemented in this gamecode type. Try moaning at the dev team\n");
return;
@ -4835,8 +4844,13 @@ void Cmd_Observe_f (void)
// call the prog function for removing a client
// this will set the body to a dead frame, among other things
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientDisconnect);
if (svs.gametype == GT_Q1QVM)
Q1QVM_DropClient(host_client);
else
{
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
PR_ExecuteProgram (svprogfuncs, pr_global_struct->ClientDisconnect);
}
sv.spawned_client_slots--;
SV_SetUpClientEdict (host_client, host_client->edict);
@ -4848,7 +4862,9 @@ void Cmd_Observe_f (void)
// FIXME, bump the client's userid?
// call the progs to get default spawn parms for the new client
if (pr_global_ptrs->SetNewParms)
if (svs.gametype == GT_Q1QVM)
Q1QVM_SetNewParms();
else if (pr_global_ptrs->SetNewParms)
PR_ExecuteProgram (svprogfuncs, pr_global_struct->SetNewParms);
for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
{
@ -4861,17 +4877,22 @@ void Cmd_Observe_f (void)
SV_SpawnSpectator ();
// call the spawn function
if (SpectatorConnect)
{
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
PR_ExecuteProgram (svprogfuncs, SpectatorConnect);
}
if (svs.gametype == GT_Q1QVM)
Q1QVM_ClientConnect(host_client);
else
{
sv_player->v->movetype = MOVETYPE_NOCLIP;
sv_player->v->model = 0;
sv_player->v->modelindex = 0;
if (SpectatorConnect)
{
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv_player);
PR_ExecuteProgram (svprogfuncs, SpectatorConnect);
}
else
{
sv_player->v->movetype = MOVETYPE_NOCLIP;
sv_player->v->model = 0;
sv_player->v->modelindex = 0;
}
}
sv.spawned_observer_slots++;

View File

@ -252,6 +252,42 @@ char *TP_ParseFunChars(char *str, qbool chat)
*out++ = (dehex(str[2]) << 4) | dehex(str[3]);
str+=4;
}
else if (str[0] == '$')
{
int c = 0;
switch (str[1])
{
case '\\': c = 0x0D; break;
case ':': c = 0x0A; break;
case '[': c = 0x10; break;
case ']': c = 0x11; break;
case 'G': c = 0x86; break;
case 'R': c = 0x87; break;
case 'Y': c = 0x88; break;
case 'B': c = 0x89; break;
case '(': c = 0x80; break;
case '=': c = 0x81; break;
case ')': c = 0x82; break;
case 'a': c = 0x83; break;
case '<': c = 0x1d; break;
case '-': c = 0x1e; break;
case '>': c = 0x1f; break;
case ',': c = 0x1c; break;
case '.': c = 0x9c; break;
case 'b': c = 0x8b; break;
case 'c':
case 'd': c = 0x8d; break;
case '$': c = '$'; break;
case '^': c = '^'; break;
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': c = str[1] -'0' + 0x12;break;
}
if (c)
{
*out++ = c;
str++;
}
str++;
}
else if (*str)
*out++ = *str++;
else