diff --git a/quakec/csaddon/src/cam.qc b/quakec/csaddon/src/cam.qc new file mode 100644 index 000000000..519cf7b89 --- /dev/null +++ b/quakec/csaddon/src/cam.qc @@ -0,0 +1,112 @@ +typedef struct +{ + int maxpoints; + int something; + vector pos[64]; +} spline_t; +typedef struct +{ + int numsplines; + spline_t spline[64]; +} splinedata_t; +static splinedata_t *splinedata; +static var float splinefile = -1; + +void() spline_init = +{ + /*precache the shader*/ + shaderforname("camsplineshader", "{\n{\nmap splinetexture.tga\nblendfunc blend\nrgbgen vertex\nalphagen vertex\n}\n}\n"); + + splinefile = fopen("spline.dat", FILE_MMAP_RW, sizeof(splinedata_t)); + if (splinefile < 0) + { + /*too lazy to create a file, just use it as a malloc*/ + splinefile = fopen("", FILE_MMAP_RW, sizeof(splinedata_t)); + } + + splinedata = (splinedata_t*)(fgets(splinefile)); + + + print("Temp test code\n"); + splinedata->numsplines = 1; + splinedata->spline[0].maxpoints = 4; + splinedata->spline[0].pos[0] = '-1024 -1024'; + splinedata->spline[0].pos[1] = '+1024 -1024'; + splinedata->spline[0].pos[2] = '+1024 +1024'; + splinedata->spline[0].pos[3] = '-1024 +1024'; + + splinedata->spline[0].pos[4] = '-1024 +1024'; + splinedata->spline[0].pos[5] = '+1024 +1024'; + splinedata->spline[0].pos[6] = '+1024 -1024'; + splinedata->spline[0].pos[7] = '-1024 -1024'; +}; +void() spline_shutdown = +{ + fclose(splinefile); + splinefile = -1; +}; + +/*called each frame*/ +void(float attime) spline_overrides = +{ + local spline_t *spline; + + /*find correct spline based upon time global*/ + + if (spline->something) + { +// setviewprop(VF_ORIGIN, somepos); +// setviewprop(VF_ANGLE, someangle); +// setviewprop(VF_AFOV, 90); + } +}; + +static void(spline_t *s) spline_draw = +{ + /*example of drawing convex polygons*/ + R_BeginPolygon("camsplineshader"); + + R_PolygonVertex(s->pos[0], '0 0', '1 1 1', 1); + R_PolygonVertex(s->pos[1], '1 0', '1 1 1', 1); + R_PolygonVertex(s->pos[2], '1 1', '1 1 1', 1); + R_PolygonVertex(s->pos[3], '0 1', '1 1 1', 1); + R_EndPolygon(); + + /*do another with the same shader*/ + R_PolygonVertex(s->pos[4], '0 0', '1 1 1', 1); + R_PolygonVertex(s->pos[5], '1 0', '1 1 1', 1); + R_PolygonVertex(s->pos[6], '1 1', '1 1 1', 1); + R_PolygonVertex(s->pos[7], '0 1', '1 1 1', 1); + R_EndPolygon(); +}; + +void() editor_spline_add = +{ + int i; + + if (splinefile < 0) + spline_init(); + + /*add visible splines to the scene*/ + for (i = 0; i < splinedata->numsplines; i+=1i) + spline_draw(&splinedata->spline[i]); + + /*sort out the overrides*/ +// spline_overrides(simtime); +}; +void(vector curmousepos) editor_spline_overlay = +{ + if (splinefile < 0) + spline_init(); + + + /*draw menu*/ + /*dunno if the light editor has any convienient code*/ + drawrawstring('0 32 0', "crappy not-implemented menu", '8 8 0', '1 1 1', 1); +}; +float(float keycode, float unicode, vector curmousepos) editor_spline_key +{ + /*print/figure out the codes yourself :P */ + return FALSE; +}; + diff --git a/quakec/csaddon/src/csaddon.qc b/quakec/csaddon/src/csaddon.qc new file mode 100644 index 000000000..d3226d212 --- /dev/null +++ b/quakec/csaddon/src/csaddon.qc @@ -0,0 +1,215 @@ +float autocvar_ca_show; +float autocvar_ca_editormode; +string autocvar_ca_colourtint; + +enum +{ + MODE_INITIAL=0, + + MODE_LIGHTEDIT=1, + MODE_SPLINEEDIT=2 +}; + +vector curmousepos; +float mousedown; + +/*the renderscene builtin in the parent progs is redirected to here*/ +void() wrap_renderscene = +{ + vector col; + /*inactive? then show nothing*/ + if (!autocvar_ca_show) + { + if (isdemo()) + spline_overrides(gettime(5)); + renderscene(); + + if (autocvar_ca_colourtint) + { + local string shdrname = strcat("tint_", autocvar_ca_colourtint); + /*make sure the shader exist*/ + shaderforname(shdrname, + "{\n" + //if we can actually use glsl... + "if $glsl\n" + "glslprogram\n" + "{\n" + "varying vec4 tf;\n" + "#ifdef VERTEX_SHADER\n" + "void main ()\n" + "{\n" + "gl_Position = tf = ftetransform();\n" + "}\n" + "#endif\n" + + "#ifdef FRAGMENT_SHADER\n" + "uniform sampler2D s_t0;\n" + "uniform sampler3D s_t1;\n" + "void main()\n" + "{\n" + "vec2 fc;\n" + "fc = tf.xy / tf.w;\n" + "vec3 raw = texture2D(s_t0, (1.0 + fc) / 2.0).rgb;\n" + + //scale+bias the sample to not clamp out at the edges + "#define LUTSIZE 16.0\n" + "vec3 scale = vec3((LUTSIZE-1.0)/LUTSIZE);\n" + "vec3 bias = vec3(1.0/(2.0*LUTSIZE));\n" + + "gl_FragColor = texture3D(s_t1, raw * scale + bias);\n" + "}\n" + "#endif\n" + "}\n" + "{\n" + "map $currentrender\n" + "}\n" + "{\n" + //16*16*16 image + "clampmap $3d:",autocvar_ca_colourtint,"\n" + "}\n" + //else (glsl not available) + "][\n" + //just don't draw anything. + "surfaceparm nodraw\n" + "]\n" + "}\n" + ); + drawpic(getproperty(VF_MIN), shdrname, getproperty(VF_SIZE), '1 1 1', 1); + } + return; + } + + /*hide hud and crosshair*/ + setproperty(VF_DRAWENGINESBAR, 0); + setproperty(VF_DRAWCROSSHAIR, 0); + + if (autocvar_ca_editormode == MODE_LIGHTEDIT) + editor_lights_add(); + else if (autocvar_ca_editormode == MODE_SPLINEEDIT) + editor_spline_add(); + + renderscene(); + + if (autocvar_ca_editormode == MODE_LIGHTEDIT) + col = '1 0 0'; + else if (curmousepos_y < 8 && curmousepos_x >= 64*(MODE_LIGHTEDIT-1) && curmousepos_x < 64*MODE_LIGHTEDIT) + col = '0 0 1'; + else + col = '1 1 1'; + drawrawstring('64 0 0'*(MODE_LIGHTEDIT-1), "LIGHTS", '8 8 0', col, 1); + + if (autocvar_ca_editormode == MODE_SPLINEEDIT) + col = '1 0 0'; + else if (curmousepos_y < 8 && curmousepos_x >= 64*(MODE_SPLINEEDIT-1) && curmousepos_x < 64*MODE_SPLINEEDIT) + col = '0 0 1'; + else + col = '1 1 1'; + drawrawstring('64 0 0'*(MODE_SPLINEEDIT-1), "SPLINES", '8 8 0', col, 1); + + if (autocvar_ca_editormode == MODE_LIGHTEDIT) + editor_lights_overlay(curmousepos); + else if (autocvar_ca_editormode == MODE_SPLINEEDIT) + editor_spline_overlay(curmousepos); + + drawcharacter(curmousepos - '4 4', '+', '8 8', '1 1 1', 1); +}; + +var float(float,float,float) orig_input_event = __NULL__; +float (float event, float parama, float paramb) wrap_InputEvent = +{ + if (autocvar_ca_show) + { + if (event == 0) + { + if (parama == 512 && curmousepos_y < 8) + { + cvar_set("ca_editormode", ftos(floor(curmousepos_x / 64)+1)); + return TRUE; + } + if (autocvar_ca_editormode == MODE_LIGHTEDIT) + { + if (editor_lights_key(parama, paramb, curmousepos)) + return TRUE; + } + else if (autocvar_ca_editormode == MODE_SPLINEEDIT) + { + if (editor_spline_key(parama, paramb, curmousepos)) + return TRUE; + } + if (parama == 512) + { + mousedown = 1; + return TRUE; + } + if (parama == 513) + { + mousedown = 2; + return TRUE; + } + } + else if (event == 1) + { + if (parama == 511+mousedown) + mousedown = FALSE; + } + else if (event == 2) + { + if (mousedown == 2) + return FALSE; + curmousepos_x += parama; + curmousepos_y += paramb; + if (curmousepos_x < 0) + curmousepos_x = 0; + if (curmousepos_y < 0) + curmousepos_y = 0; + if (curmousepos_x > 640) + curmousepos_x = 640; + if (curmousepos_y > 480) + curmousepos_y = 480; + return TRUE; + } + else if (event == 3) + { + curmousepos_x = parama; + curmousepos_y = paramb; + if (mousedown == 2) + return FALSE; + return TRUE; + } + } + + if (orig_input_event) + return orig_input_event(event, parama, paramb); + return FALSE; +} + + + +/*this is a fallback function, in case the main progs does not have one*/ +void(float width, float height, float do2d) CSQC_UpdateView = +{ + clearscene(); + setproperty(VF_DRAWENGINESBAR, 1); + setproperty(VF_DRAWCROSSHAIR, 1); + addentities(intermission?MASK_ENGINE:(MASK_VIEWMODEL|MASK_ENGINE)); + wrap_renderscene(); +}; + +/*this is a fallback function, in case the main progs does not have one*/ +float (float event, float parama, float paramb) CSQC_InputEvent = +{ + return wrap_InputEvent(event, parama, paramb); +}; + +void(float prevprogs) init = +{ + if (prevprogs >= 0) + { + /*its easy to wrap a builtin*/ + externset(0, wrap_renderscene, "renderscene"); + + /*wrap the parent's input event function*/ + orig_input_event = externvalue(0, "CSQC_InputEvent"); + externset(0, wrap_InputEvent, "CSQC_InputEvent"); + } +}; diff --git a/quakec/csaddon/src/csaddon.src b/quakec/csaddon/src/csaddon.src new file mode 100644 index 000000000..1f8eeb3b5 --- /dev/null +++ b/quakec/csaddon/src/csaddon.src @@ -0,0 +1,7 @@ +../csaddon.dat +//pr_dumpplatform -FFTE -Fdefines -TCS -O csplat +csplat.qc + +editor_lights.qc +cam.qc +csaddon.qc diff --git a/quakec/csaddon/src/editor_lights.qc b/quakec/csaddon/src/editor_lights.qc new file mode 100644 index 000000000..bdffa8498 --- /dev/null +++ b/quakec/csaddon/src/editor_lights.qc @@ -0,0 +1,313 @@ +/*FTE has some special light editing builtins, I don't ever expect them to be standard or anything, but they're handy for this*/ + +/*you probably want to change this if you're running hexen2*/ +var string autocvar_cg_editor_lightmodel = "progs/s_light.spr"; + +static float selectedlight; +static float editfield; +static string editvalue; +static entity tempent; +void() editor_lights_add = +{ + float l; + if (!tempent) + tempent = spawn(); + + l = dynamiclight_get(-1, -1); + precache_model(autocvar_cg_editor_lightmodel); /*just to silence it*/ + setmodel(tempent, autocvar_cg_editor_lightmodel); + while(l > 0) + { + l = l-1; + if (l == selectedlight) + { + if (gettime(0)*5 & 1) + continue; + tempent.effects |= 8192; + } + else + tempent.effects &~= 8192; + if (!(float)dynamiclight_get(l, LFIELD_RADIUS)) + continue; + setorigin(tempent, dynamiclight_get(l, LFIELD_ORIGIN)); + addentity(tempent); + } +}; + +static string fldname[10] = { + "bad", + "num", + "org", + "rgb", + "rad", + "flg", + "sty", + "ang", + "fov", + "???" +}; +static string(float fld, float foredit) readfield = +{ + switch(fld) + { + case 1: + if (foredit) + return ftos(selectedlight); + return strcat(ftos(selectedlight), " / ", ftos(dynamiclight_get(-1, -1))); + case 2: + return vtos(dynamiclight_get(selectedlight, LFIELD_ORIGIN)); + case 3: + return vtos(dynamiclight_get(selectedlight, LFIELD_COLOUR)); + case 4: + return ftos(dynamiclight_get(selectedlight, LFIELD_RADIUS)); + case 5: + float fl = (float)dynamiclight_get(selectedlight, LFIELD_FLAGS); + string ret; + ret = strcat(ret, (fl & LFLAG_NORMALMODE)?"d":""); + ret = strcat(ret, (fl & LFLAG_REALTIMEMODE)?"w":""); + ret = strcat(ret, (fl & LFLAG_LIGHTMAP)?"l":""); + ret = strcat(ret, (fl & LFLAG_FLASHBLEND)?"f":""); + ret = strcat(ret, (fl & LFLAG_NOSHADOWS)?"c":""); + ret = strcat(ret, (fl & LFLAG_SHADOWMAP)?"s":""); + ret = strcat(ret, (fl & LFLAG_CREPUSCULAR)?"r":""); + return ret; + case 6: + return ftos(dynamiclight_get(selectedlight, LFIELD_STYLE)); + case 7: + return vtos(dynamiclight_get(selectedlight, LFIELD_ANGLES)); + case 8: + return ftos(dynamiclight_get(selectedlight, LFIELD_FOV)); + default: + return ""; + } +}; + +static void(float fld, string newval) writefield = +{ + switch(fld) + { + case 1: + selectedlight = stof(newval); + return; + case 2: + dynamiclight_set(selectedlight, LFIELD_ORIGIN, stov(newval)); + return; + case 3: + dynamiclight_set(selectedlight, LFIELD_COLOUR, stov(newval)); + return; + case 4: + dynamiclight_set(selectedlight, LFIELD_RADIUS, stof(newval)); + return; + case 5: + float fl; + if (strstrofs(newval, "d")>=0) fl |= LFLAG_NORMALMODE; + if (strstrofs(newval, "w")>=0) fl |= LFLAG_REALTIMEMODE; + if (strstrofs(newval, "l")>=0) fl |= LFLAG_LIGHTMAP; + if (strstrofs(newval, "f")>=0) fl |= LFLAG_FLASHBLEND; + if (strstrofs(newval, "c")>=0) fl |= LFLAG_NOSHADOWS; + if (strstrofs(newval, "s")>=0) fl |= LFLAG_SHADOWMAP; + if (strstrofs(newval, "r")>=0) fl |= LFLAG_CREPUSCULAR; + dynamiclight_set(selectedlight, LFIELD_FLAGS, fl); + return; + case 6: + dynamiclight_set(selectedlight, LFIELD_STYLE, stof(newval)); + return; + case 7: + dynamiclight_set(selectedlight, LFIELD_ANGLES, stov(newval)); + return; + case 8: + dynamiclight_set(selectedlight, LFIELD_FOV, stof(newval)); + default: + return; + } +}; + +void(vector m) editor_lights_overlay = +{ + float i; + string s; + vector col; + + m_y = floor((m_y - 32) / 8); + + for (i = 1; i <= 8; i++) + { + if (editfield == i) + s = editvalue; + else + s = readfield(i, 0); + s = strcat(ftos(i), " ", fldname[i], ": ", s); + + if (editfield == i) + col = '1 0 0'; + else if (m_y == i && m_x < 64) + col = '0 0 1'; + else + col = '1 1 1'; + + drawrawstring('0 32 0' + '0 8 0' * i, s, '8 8 0', col, 1); + } + i+=1; + + + if (editfield == 5) + { + drawrawstring('0 32 0' + '0 8 0' * i, "d: dynamic mode\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "w: realtime world lights mode\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "l: lightmap hack (not valid above index 32)\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "f: flashblend coronas\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "c: does not cast shadows\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "s: shadowmapped light\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "r: crepuscular rays\n", '8 8 0', '1 1 1', 1); i+=1; + } + else + { + drawrawstring('0 32 0' + '0 8 0' * i, "+/- change selected light\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "mouse also selects lights\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "m moves the light to the crosshair\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "i inserts new light\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "p points the light to aim at the crosshair\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "[ and ] move the light towards/away from indicated plane\n", '8 8 0', '1 1 1', 1); i+=1; + drawrawstring('0 32 0' + '0 8 0' * i, "don't forget to save\n", '8 8 0', '1 1 1', 1); i+=1; + } +}; + +static void(vector fwd, vector vorg) selectbestlight = +{ + float l, b=selectedlight, d, bd; + vector ldir; + l = dynamiclight_get(-1, -1); + while(l > 0) + { + l--; + ldir = dynamiclight_get(l, LFIELD_ORIGIN); + ldir = normalize(ldir - vorg); + d = fwd*ldir; + if (d > bd) + { + bd = d; + b = l; + } + } + selectedlight = b; +}; + +float(float keyc, float unic, vector m) editor_lights_key = +{ + vector t = unproject(m + '0 0 8192'); + vector o = unproject(m); + string ns; + if (keyc == 512) + { + if (editfield) + { + writefield(editfield, editvalue); + strunzone(editvalue); + editfield = 0; + } + editfield = floor((m_y - 32) / 8); + if (editfield <= 0 || editfield > 8 || m_x >= 64) + { + editfield = 0; + + selectbestlight(t - o, o); + } + else + editvalue = strzone(readfield(editfield, 1)); + } + else if (editfield) + { + ns = strcat(editvalue); + if (keyc == 10 || keyc == 13) + { + writefield(editfield, ns); + editfield = 0; + } + else if (keyc == 127) + { + if (ns != "") + ns = substring(ns, 0, -2); + } + else if (keyc == 8) + { + ns = ""; + } + else + ns = strcat(ns, chr2str(unic)); + + ns = strzone(ns); + strunzone(editvalue); + editvalue = ns; + + writefield(editfield, ns); + } + else if (keyc >= '0' && keyc <= '9') + { + editfield = keyc - '0'; + editvalue = strzone(readfield(editfield, 1)); + } + else if (keyc == '=') + selectedlight++; + else if (keyc == '-') + selectedlight--; + else if (keyc == 'n') + localcmd("noclip\n"); +// else if (keyc == 's') +// { +// selectbestlight(t - o, o); +// } + else if (keyc == 'm') + { + traceline(o, t, TRUE, world); + dynamiclight_set(selectedlight, LFIELD_ORIGIN, trace_endpos + trace_plane_normal*4); + } + else if (keyc == 'p') + { + traceline(o, t, TRUE, world); + vector ang = vectoangles((trace_endpos + trace_plane_normal*4) - (vector)dynamiclight_get(selectedlight, LFIELD_ORIGIN)); + ang_x *= -1; + dynamiclight_set(selectedlight, LFIELD_ANGLES, ang); + + /*if we're pointing the light at something, it should probably have a fov*/ + if (!(float)dynamiclight_get(selectedlight, LFIELD_ORIGIN)) + dynamiclight_set(selectedlight, LFIELD_FOV, 90); + } + else if (keyc == 'i') + { + for (selectedlight = 32; ; selectedlight++) + { + if (!(float)dynamiclight_get(selectedlight, LFIELD_RADIUS)) + { + /*reset the light's properties*/ + dynamiclight_set(selectedlight, LFIELD_RADIUS, 300); + dynamiclight_set(selectedlight, LFIELD_COLOUR, '1 1 1'); + dynamiclight_set(selectedlight, LFIELD_FOV, 0); + dynamiclight_set(selectedlight, LFIELD_STYLE, 0); + dynamiclight_set(selectedlight, LFIELD_ANGLES, '0 0 0'); + dynamiclight_set(selectedlight, LFIELD_FLAGS, LFLAG_REALTIMEMODE); + + /*place it at the pointed location*/ + traceline(o, t, TRUE, world); + dynamiclight_set(selectedlight, LFIELD_ORIGIN, trace_endpos + trace_plane_normal*4); + break; + } + } + } + else if (keyc == '[') + { + o = getproperty(11); + traceline(o, t, TRUE, world); + dynamiclight_set(selectedlight, LFIELD_ORIGIN, dynamiclight_get(selectedlight, LFIELD_ORIGIN) - trace_plane_normal); + } + else if (keyc == ']') + { + o = getproperty(11); + traceline(o, t, TRUE, world); + dynamiclight_set(selectedlight, LFIELD_ORIGIN, dynamiclight_get(selectedlight, LFIELD_ORIGIN) + trace_plane_normal); + } + else if (keyc == 127) + dynamiclight_set(selectedlight, LFIELD_RADIUS, 0); + else + return FALSE; + return TRUE; +}; diff --git a/quakec/csaddon/textures/basergb.png b/quakec/csaddon/textures/basergb.png new file mode 100644 index 000000000..fc0f026e0 Binary files /dev/null and b/quakec/csaddon/textures/basergb.png differ diff --git a/quakec/csaddon/textures/grey.png b/quakec/csaddon/textures/grey.png new file mode 100644 index 000000000..7a03ea7ec Binary files /dev/null and b/quakec/csaddon/textures/grey.png differ