ui_node_material_editor.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 1997-2001 Id Software, Inc.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "../../client.h"
00027 #include "../ui_main.h"
00028 #include "../ui_data.h"
00029 #include "../ui_windows.h"
00030 #include "../ui_nodes.h"
00031 #include "../ui_actions.h"
00032 #include "../ui_render.h"
00033 #include "../ui_parse.h"
00034 #include "ui_node_abstractnode.h"
00035 #include "ui_node_abstractscrollable.h"
00036 #include "../../cl_video.h"
00037 #include "../../renderer/r_image.h"
00038 #include "../../renderer/r_draw.h"
00039 #include "../../renderer/r_model.h"
00040 #include "ui_node_material_editor.h"
00041 
00042 #define EXTRADATA(node) UI_EXTRADATA(node, abstractScrollableExtraData_t)
00043 
00044 /*#define ANYIMAGES*/
00046 #define IMAGE_WIDTH 64
00047 
00048 typedef struct materialDescription_s {
00049     const char *name;
00050     const int stageFlag;
00051 } materialDescription_t;
00052 
00053 static const materialDescription_t materialDescriptions[] = {
00054     {"texture", STAGE_TEXTURE},
00055     {"envmap", STAGE_ENVMAP},
00056     {"blend", STAGE_BLEND},
00057     {"color", STAGE_COLOR},
00058     {"pulse", STAGE_PULSE},
00059     {"stretch", STAGE_STRETCH},
00060     {"rotate", STAGE_ROTATE},
00061     {"scroll.s", STAGE_SCROLL_S},
00062     {"scroll.t", STAGE_SCROLL_T},
00063     {"scale.s", STAGE_SCALE_S},
00064     {"scale.t", STAGE_SCALE_T},
00065     {"terrain", STAGE_TERRAIN},
00066     {"tape", STAGE_TAPE},
00067     {"lightmap", STAGE_LIGHTMAP},
00068     {"anim", STAGE_ANIM},
00069     {"dirtmap", STAGE_DIRTMAP},
00070 
00071     {NULL, 0}
00072 };
00073 
00074 static materialStage_t *UI_MaterialEditorGetStage (material_t *material, int stageIndex)
00075 {
00076     materialStage_t *materialStage = material->stages;
00077     while (stageIndex-- > 0) {
00078         if (materialStage)
00079             materialStage = materialStage->next;
00080         else
00081             break;
00082     }
00083     return materialStage;
00084 }
00085 
00089 static int UI_MaterialEditorNodeGetImageCount (uiNode_t *node)
00090 {
00091     int i;
00092     int cnt = 0;
00093 
00094     for (i = 0; i < r_numImages; i++) {
00095 #ifndef ANYIMAGES
00096         const image_t *image = &r_images[i];
00097         /* filter */
00098         if (image->type != it_world)
00099             continue;
00100 
00101         if (strstr(image->name, "tex_common"))
00102             continue;
00103 #endif
00104         cnt++;
00105     }
00106     return cnt;
00107 }
00108 
00112 static void UI_MaterialEditorNodeUpdateView (uiNode_t *node, qboolean reset)
00113 {
00114     const int imageCount = UI_MaterialEditorNodeGetImageCount(node);
00115     const int imagesPerLine = (node->size[0] - node->padding) / (IMAGE_WIDTH + node->padding);
00116     const int imagesPerColumn = (node->size[1] - node->padding) / (IMAGE_WIDTH + node->padding);
00117 
00118     /* update view */
00119     if (imagesPerLine > 0 && imagesPerColumn > 0) {
00120         const int pos = reset ? 0 : -1;
00121         UI_AbstractScrollableNodeSetY(node, pos, imagesPerColumn, imageCount / imagesPerLine);
00122     } else
00123         UI_AbstractScrollableNodeSetY(node, 0, 0, 0);
00124 }
00125 
00129 static void UI_MaterialEditorNodeDraw (uiNode_t *node)
00130 {
00131     int i;
00132     vec2_t pos;
00133     int cnt = 0;
00134     int cntView = 0;
00135     const int imagesPerLine = (node->size[0] - node->padding) / (IMAGE_WIDTH + node->padding);
00136 
00137     if (UI_AbstractScrollableNodeIsSizeChange(node))
00138         UI_MaterialEditorNodeUpdateView(node, qfalse);
00139 
00140     /* width too small to display anything */
00141     if (imagesPerLine <= 0)
00142         return;
00143 
00144     UI_GetNodeAbsPos(node, pos);
00145 
00146     /* display images */
00147     for (i = 0; i < r_numImages; i++) {
00148         image_t *image = &r_images[i];
00149         vec2_t imagepos;
00150 
00151 #ifndef ANYIMAGES
00152         /* filter */
00153         if (image->type != it_world)
00154             continue;
00155 
00156         if (strstr(image->name, "tex_common"))
00157             continue;
00158 #endif
00159 
00160         /* skip images before the scroll position */
00161         if (cnt / imagesPerLine < EXTRADATA(node).scrollY.viewPos) {
00162             cnt++;
00163             continue;
00164         }
00165 
00167         imagepos[0] = pos[0] + node->padding + (cntView % imagesPerLine) * (IMAGE_WIDTH + node->padding);
00168         imagepos[1] = pos[1] + node->padding + (cntView / imagesPerLine) * (IMAGE_WIDTH + node->padding);
00169 
00170         /* vertical overflow */
00171         if (imagepos[1] + IMAGE_WIDTH + node->padding >= pos[1] + node->size[1])
00172             break;
00173 
00174         if (i == node->num) {
00175 #define MARGIN 3
00176             R_DrawRect(imagepos[0] - MARGIN, imagepos[1] - MARGIN, IMAGE_WIDTH + MARGIN * 2, IMAGE_WIDTH + MARGIN * 2, node->selectedColor, 2, 0xFFFF);
00177 #undef MARGIN
00178         }
00179 
00180         UI_DrawNormImage(imagepos[0], imagepos[1], IMAGE_WIDTH, IMAGE_WIDTH, 0, 0, 0, 0, image);
00181 
00182         cnt++;
00183         cntView++;
00184     }
00185 }
00186 
00190 static int UI_MaterialEditorNodeGetImageAtPosition (uiNode_t *node, int x, int y)
00191 {
00192     int i;
00193     vec2_t pos;
00194     int cnt = 0;
00195     int cntView = 0;
00196     const int imagesPerLine = (node->size[0] - node->padding) / (IMAGE_WIDTH + node->padding);
00197     const int imagesPerColumn = (node->size[1] - node->padding) / (IMAGE_WIDTH + node->padding);
00198     int columnRequested;
00199     int lineRequested;
00200 
00201     UI_NodeAbsoluteToRelativePos(node, &x, &y);
00202 
00203     /* have we click between 2 images? */
00204     if (((x % (IMAGE_WIDTH + node->padding)) < node->padding)
00205         || ((y % (IMAGE_WIDTH + node->padding)) < node->padding))
00206         return -1;
00207 
00208     /* get column and line of the image */
00209     columnRequested = x / (IMAGE_WIDTH + node->padding);
00210     lineRequested = y / (IMAGE_WIDTH + node->padding);
00211 
00212     /* have we click outside? */
00213     if (columnRequested >= imagesPerLine || lineRequested >= imagesPerColumn)
00214         return -1;
00215 
00216     UI_GetNodeAbsPos(node, pos);
00217 
00218     /* check images */
00219     for (i = 0; i < r_numImages; i++) {
00220 #ifndef ANYIMAGES
00221         /* filter */
00222         image_t *image = &r_images[i];
00223         if (image->type != it_world)
00224             continue;
00225 
00226         if (strstr(image->name, "tex_common"))
00227             continue;
00228 #endif
00229 
00230         /* skip images before the scroll position */
00231         if (cnt / imagesPerLine < EXTRADATA(node).scrollY.viewPos) {
00232             cnt++;
00233             continue;
00234         }
00235 
00236         if (cntView % imagesPerLine == columnRequested && cntView / imagesPerLine == lineRequested)
00237             return i;
00238 
00239         /* vertical overflow */
00240         if (cntView / imagesPerLine > lineRequested)
00241             break;
00242 
00243         cnt++;
00244         cntView++;
00245     }
00246 
00247     return -1;
00248 }
00249 
00250 static void UI_MaterialEditorStagesToName (const materialStage_t *stage, char *buf, size_t size)
00251 {
00252     const materialDescription_t *md = materialDescriptions;
00253 
00254     while (md->name) {
00255         if (stage->flags & md->stageFlag)
00256             Q_strcat(buf, va("%s ", md->name), size);
00257         md++;
00258     }
00259 }
00260 
00266 static void UI_MaterialEditorUpdate (image_t *image, materialStage_t *materialStage)
00267 {
00268     linkedList_t *materialStagesList = NULL;
00269 
00270     if (image->normalmap == NULL)
00271         UI_ExecuteConfunc("hideshaders true 0 0 0 0");
00272     else
00273         UI_ExecuteConfunc("hideshaders false %f %f %f %f", image->material.bump,
00274                 image->material.hardness, image->material.parallax, image->material.specular);
00275 
00276     if (image->normalmap == NULL)
00277         Cvar_Set("me_imagename", image->name);
00278     else
00279         Cvar_Set("me_imagename", va("%s (nm)", image->name));
00280 
00281     if (!image->material.num_stages) {
00282         UI_ExecuteConfunc("hidestages true");
00283     } else {
00284         int i;
00285         if (materialStage) {
00286             const char *stageType = Cvar_GetString("me_stagetype");
00287             if (stageType[0] == '\0')
00288                 stageType = "stretch";
00289             UI_ExecuteConfunc("hidestages false %s", stageType);
00290         } else
00291             Cvar_Set("me_stage_id", "-1");
00292         for (i = 0; i < image->material.num_stages; i++) {
00293             const materialStage_t *stage = UI_MaterialEditorGetStage(&image->material, i);
00294             char stageName[MAX_VAR] = "stage ";
00295             if (stage == materialStage) {
00296                 UI_ExecuteConfunc("updatestagevalues %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
00297                         stage->rotate.hz, stage->rotate.deg,
00298                         stage->stretch.hz, stage->stretch.dhz, stage->stretch.amp, stage->stretch.damp,
00299                         stage->pulse.hz, stage->pulse.dhz,
00300                         stage->scroll.ds, stage->scroll.dt, stage->scroll.s, stage->scroll.t,
00301                         stage->scale.s, stage->scale.t);
00302             }
00303             UI_MaterialEditorStagesToName(stage, stageName, sizeof(stageName) - 1);
00304             LIST_AddString(&materialStagesList, stageName);
00305         }
00306     }
00307     UI_RegisterLinkedListText(TEXT_MATERIAL_STAGES, materialStagesList);
00308 }
00309 
00315 static int UI_MaterialEditorNameToStage (const char *stageName)
00316 {
00317     const materialDescription_t *md = materialDescriptions;
00318 
00319     while (md->name) {
00320         if (!strncmp(md->name, stageName, strlen(md->name)))
00321             return md->stageFlag;
00322         md++;
00323     }
00324     return -1;
00325 }
00326 
00327 static void UI_MaterialEditorMouseDown (uiNode_t *node, int x, int y, int button)
00328 {
00329     int id;
00330     if (button != K_MOUSE1)
00331         return;
00332 
00333     id = UI_MaterialEditorNodeGetImageAtPosition(node, x, y);
00334     if (id == -1)
00335         return;
00336 
00338     /* have we selected a new image? */
00339     if (node->num != id) {
00340         image_t *image = &r_images[id];
00341         UI_MaterialEditorUpdate(image, NULL);
00342 
00343         node->num = id;
00344 
00345         if (node->onChange)
00346             UI_ExecuteEventActions(node, node->onChange);
00347     }
00348 }
00349 
00353 static void UI_MaterialEditorNodeInit (uiNode_t *node)
00354 {
00355     node->num = -1;
00356     UI_MaterialEditorNodeUpdateView(node, qtrue);
00357 }
00358 
00362 static void UI_MaterialEditorNodeWheel (uiNode_t *node, qboolean down, int x, int y)
00363 {
00364     const int diff = (down) ? 1 : -1;
00365     UI_AbstractScrollableNodeScrollY(node, diff);
00366 }
00367 
00368 static void UI_MaterialEditorStart_f (void)
00369 {
00370     /* material editor only makes sense in battlescape mode */
00371 #ifndef ANYIMAGES
00372     if (cls.state != ca_active) {
00373         Com_Printf("Material editor is only usable in battlescape mode\n");
00374         UI_PopWindow(qfalse);
00375         return;
00376     }
00377 #endif
00378 }
00379 
00380 static const value_t materialValues[] = {
00381     {"bump", V_FLOAT, offsetof(material_t, bump), 0},
00382     {"parallax", V_FLOAT, offsetof(material_t, parallax), 0},
00383     {"specular", V_FLOAT, offsetof(material_t, specular), 0},
00384     {"hardness", V_FLOAT, offsetof(material_t, hardness), 0},
00385 
00386     {NULL, V_NULL, 0, 0},
00387 };
00388 
00389 
00390 static const value_t materialStageValues[] = {
00391     {"rotate.hz", V_FLOAT, offsetof(materialStage_t, rotate.deg), 0},
00392     {"rotate.deg", V_FLOAT, offsetof(materialStage_t, rotate.hz), 0},
00393     {"stretch.hz", V_FLOAT, offsetof(materialStage_t, stretch.hz), 0},
00394     {"stretch.dhz", V_FLOAT, offsetof(materialStage_t, stretch.dhz), 0},
00395     {"stretch.amp", V_FLOAT, offsetof(materialStage_t, stretch.amp), 0},
00396     {"stretch.damp", V_FLOAT, offsetof(materialStage_t, stretch.damp), 0},
00397     {"pulse.hz", V_FLOAT, offsetof(materialStage_t, pulse.hz), 0},
00398     {"pulse.dhz", V_FLOAT, offsetof(materialStage_t, pulse.dhz), 0},
00399     {"scroll.s", V_FLOAT, offsetof(materialStage_t, scroll.s), 0},
00400     {"scroll.t", V_FLOAT, offsetof(materialStage_t, scroll.t), 0},
00401     {"scroll.ds", V_FLOAT, offsetof(materialStage_t, scroll.ds), 0},
00402     {"scroll.dt", V_FLOAT, offsetof(materialStage_t, scroll.dt), 0},
00403     {"scale.s", V_FLOAT, offsetof(materialStage_t, scale.s), 0},
00404     {"scale.t", V_FLOAT, offsetof(materialStage_t, scale.t), 0},
00405     {"terrain.floor", V_FLOAT, offsetof(materialStage_t, terrain.floor), 0},
00406     {"terrain.ceil", V_FLOAT, offsetof(materialStage_t, terrain.ceil), 0},
00407     {"tape.floor", V_FLOAT, offsetof(materialStage_t, tape.floor), 0},
00408     {"tape.ceil", V_FLOAT, offsetof(materialStage_t, tape.ceil), 0},
00409     {"tape.center", V_FLOAT, offsetof(materialStage_t, tape.center), 0},
00410     {"anim.frames", V_INT, offsetof(materialStage_t, anim.num_frames), 0},
00411     {"anim.dframe", V_INT, offsetof(materialStage_t, anim.dframe), 0},
00412     {"anim.dtime", V_FLOAT, offsetof(materialStage_t, anim.dtime), 0},
00413     {"anim.fps", V_FLOAT, offsetof(materialStage_t, anim.fps), 0},
00414     {"dirt.intensity", V_FLOAT, offsetof(materialStage_t, dirt.intensity), 0},
00415     {"blend.src", V_INT, offsetof(materialStage_t, blend.src), 0},
00416     {"blend.dest", V_INT, offsetof(materialStage_t, blend.dest), 0},
00417 
00418     {NULL, V_NULL, 0, 0},
00419 };
00420 
00421 static void UI_MaterialEditorChangeValue_f (void)
00422 {
00423     image_t *image;
00424     int id, stageType;
00425     const char *var, *value;
00426     size_t bytes;
00427 
00428     if (Cmd_Argc() < 5) {
00429         Com_Printf("Usage: %s <image index> <stage index> <variable> <value>\n", Cmd_Argv(0));
00430         return;
00431     }
00432 
00433     id = atoi(Cmd_Argv(1));
00434     if (id < 0 || id >= r_numImages) {
00435         Com_Printf("Given image index (%i) is out of bounds\n", id);
00436         return;
00437     }
00438 
00439     var = Cmd_Argv(3);
00440     value = Cmd_Argv(4);
00441 
00442     image = &r_images[id];
00443 
00444     stageType = UI_MaterialEditorNameToStage(var);
00445     if (stageType == -1) {
00446         const value_t *val = UI_FindPropertyByName(materialValues, var);
00447         if (!val) {
00448             Com_Printf("Could not find material variable for '%s'\n", var);
00449             return;
00450         }
00451         Com_ParseValue(&image->material, value, val->type, val->ofs, val->size, &bytes);
00452     } else {
00453         materialStage_t *stage;
00454         int stageID;
00455         const value_t *val = UI_FindPropertyByName(materialStageValues, var);
00456 
00457         if (!val) {
00458             Com_Printf("Could not find material stage variable for '%s'\n", var);
00459             return;
00460         }
00461 
00462         stageID = atoi(Cmd_Argv(2));
00463         if (stageID < 0 || stageID >= image->material.num_stages) {
00464             Com_Printf("Given stage index (%i) is out of bounds\n", stageID);
00465             return;
00466         }
00467 
00468         stage = UI_MaterialEditorGetStage(&image->material, stageID);
00469         assert(stage);
00470 
00471         stage->flags |= stageType;
00472 
00473         Com_ParseValue(stage, value, val->type, val->ofs, val->size, &bytes);
00474 
00475         /* a texture or envmap means render it */
00476         if (stage->flags & (STAGE_TEXTURE | STAGE_ENVMAP))
00477             stage->flags |= STAGE_RENDER;
00478 
00479         if (stage->flags & (STAGE_TAPE | STAGE_TERRAIN | STAGE_DIRTMAP))
00480             stage->flags |= STAGE_LIGHTING;
00481     }
00482 
00483     R_ModReloadSurfacesArrays();
00484 }
00485 
00486 static void UI_MaterialEditorSelectStage_f (void)
00487 {
00488     image_t *image;
00489     int id, stageID;
00490     materialStage_t *materialStage;
00491 
00492     if (Cmd_Argc() < 3) {
00493         Com_Printf("Usage: %s <image index> <stage index>\n", Cmd_Argv(0));
00494         return;
00495     }
00496 
00497     id = atoi(Cmd_Argv(1));
00498     if (id < 0 || id >= r_numImages) {
00499         Com_Printf("Given image index (%i) is out of bounds\n", id);
00500         return;
00501     }
00502 
00503     image = &r_images[id];
00504 
00505     stageID = atoi(Cmd_Argv(2));
00506     if (stageID < 0 || stageID >= image->material.num_stages) {
00507         Com_Printf("Given stage index (%i) is out of bounds\n", stageID);
00508         return;
00509     }
00510 
00511     materialStage = UI_MaterialEditorGetStage(&image->material, stageID);
00512     UI_MaterialEditorUpdate(image, materialStage);
00513 }
00514 
00515 static void UI_MaterialEditorRemoveStage_f (void)
00516 {
00517     image_t *image;
00518     int id, stageID;
00519 
00520     if (Cmd_Argc() < 3) {
00521         Com_Printf("Usage: %s <image index> <stage index>\n", Cmd_Argv(0));
00522         return;
00523     }
00524 
00525     id = atoi(Cmd_Argv(1));
00526     if (id < 0 || id >= r_numImages) {
00527         Com_Printf("Given image index (%i) is out of bounds\n", id);
00528         return;
00529     }
00530 
00531     image = &r_images[id];
00532 
00533     stageID = atoi(Cmd_Argv(2));
00534     if (stageID < 0 || stageID >= image->material.num_stages) {
00535         Com_Printf("Given stage index (%i) is out of bounds\n", stageID);
00536         return;
00537     }
00538 
00539     if (stageID == 0) {
00540         materialStage_t *s = image->material.stages;
00541         image->material.stages = s->next;
00542         Mem_Free(s);
00543     } else {
00544         materialStage_t *sParent = UI_MaterialEditorGetStage(&image->material, stageID - 1);
00545         materialStage_t *s = sParent->next;
00546         sParent->next = s->next;
00547         Mem_Free(s);
00548     }
00549 
00550     image->material.num_stages--;
00551 
00552     UI_MaterialEditorUpdate(image, NULL);
00553 }
00554 
00555 static void UI_MaterialEditorNewStage_f (void)
00556 {
00557     material_t *m;
00558     materialStage_t *s;
00559     int id;
00560 
00561     if (Cmd_Argc() < 2) {
00562         Com_Printf("Usage: %s <image index>\n", Cmd_Argv(0));
00563         return;
00564     }
00565 
00566     id = atoi(Cmd_Argv(1));
00567     if (id < 0 || id >= r_numImages) {
00568         Com_Printf("Given image index (%i) is out of bounds\n", id);
00569         return;
00570     }
00571 
00572     m = &r_images[id].material;
00573     s = Mem_PoolAlloc(sizeof(*s), vid_imagePool, 0);
00574     m->num_stages++;
00575 
00576     /* append the stage to the chain */
00577     if (!m->stages)
00578         m->stages = s;
00579     else {
00580         materialStage_t *ss = m->stages;
00581         while (ss->next)
00582             ss = ss->next;
00583         ss->next = s;
00584     }
00585 
00586     UI_MaterialEditorUpdate(&r_images[id], s);
00587 }
00588 
00589 void UI_RegisterMaterialEditorNode (uiBehaviour_t *behaviour)
00590 {
00591     behaviour->name = "material_editor";
00592     behaviour->extends = "abstractscrollable";
00593     behaviour->draw = UI_MaterialEditorNodeDraw;
00594     behaviour->init = UI_MaterialEditorNodeInit;
00595     behaviour->mouseDown = UI_MaterialEditorMouseDown;
00596     behaviour->mouseWheel = UI_MaterialEditorNodeWheel;
00597 
00598     Cmd_AddCommand("mn_materialeditor_removestage", UI_MaterialEditorRemoveStage_f, "Removes the selected material stage");
00599     Cmd_AddCommand("mn_materialeditor_newstage", UI_MaterialEditorNewStage_f, "Creates a new material stage for the current selected material");
00600     Cmd_AddCommand("mn_materialeditor_selectstage", UI_MaterialEditorSelectStage_f, "Select a given material stage");
00601     Cmd_AddCommand("mn_materialeditor_changevalue", UI_MaterialEditorChangeValue_f, "Initializes the material editor window");
00602     Cmd_AddCommand("mn_materialeditor", UI_MaterialEditorStart_f, "Initializes the material editor window");
00603 }

Generated by  doxygen 1.6.2