/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
--- HISTORICAL COMMENTS FOLLOW ---
* $Logfile: /DescentIII/Main/editor/RoomUVs.cpp $
* $Revision: 1.1.1.1 $
* $Date: 2003-08-26 03:57:38 $
* $Author: kevinb $
*
* Code to deal with texturing rooms
*
* $Log: not supported by cvs2svn $
*
* 9 9/30/99 6:35p Matt
* Added code to scale the UVs of a texture based on the size of the
* texture when the texture is applied to a face. This will cause the
* applied texture to have the make 3D texel size at the old texture.
*
* 8 4/25/99 2:38p Gwar
* brought in HRoom.cpp and RoomUVs.cpp, and several misc game functions
* were added to globals.cpp to make it possible
*
* 7 10/21/98 1:27p Jason
* fixed texture u2,v2 sliding problems
*
* 6 10/07/98 3:19p Matt
* Cleaned up and fixed Mike's old texture UV calculation code. Who ever
* told that boy he could do 3D?
*
* 5 4/02/98 12:23p Jason
* trimmed some fat from our structures
*
* 4 12/23/97 1:33p Samir
* Added pserror.h
*
* 3 9/17/97 11:57a Matt
* Ripped out segment code
*
* 2 7/18/97 7:38p Jason
* finished room/terrain texture modifications
*
* $NoKeywords: $
*/
#include "RoomUVs.h"
#ifndef NEWEDITOR
#include "d3edit.h"
#else
#include "..\neweditor\globals.h"
#endif
#include "pserror.h"
// returns the magnatude of the 2d vector
static float zhypot(float a, float b) { return sqrt(a * a + b * b); }
// Given u,v coordinates at two vertices, assign u,v coordinates to the other vertices on a face.
// va, vb = face-relative vertex indices corresponding to uva, uvb. Ie, they are always in 0..num_verts_in_face
void AssignUVsToFace(room *rp, int facenum, roomUVL *uva, roomUVL *uvb, int va, int vb) {
face *fp = &rp->faces[facenum];
int nv = fp->num_verts;
int vlo, vhi;
vector fvec, rvec, tvec;
roomUVL ruvmag, fuvmag, uvlo, uvhi;
float fmag, mag01;
int i;
float saveu2[MAX_VERTS_PER_FACE], savev2[MAX_VERTS_PER_FACE];
for (i = 0; i < fp->num_verts; i++) {
saveu2[i] = fp->face_uvls[i].u2;
savev2[i] = fp->face_uvls[i].v2;
}
ASSERT((va < nv) && (vb < nv));
ASSERT((abs(va - vb) == 1) || (abs(va - vb) == nv - 1)); // make sure the verticies specify an edge
// We want vlo precedes vhi, ie vlo < vhi, or vlo = num_verts, vhi = 0
if (va == ((vb + 1) % nv)) { // va = vb + 1
vlo = vb;
vhi = va;
uvlo = *uvb;
uvhi = *uva;
} else {
vlo = va;
vhi = vb;
uvlo = *uva;
uvhi = *uvb;
}
ASSERT(((vlo + 1) % nv) == vhi); // If we are on an edge, then uvhi is one more than uvlo (mod num_verts)
fp->face_uvls[vlo] = uvlo;
fp->face_uvls[vhi] = uvhi;
// Now we have vlo precedes vhi, compute vertices ((vhi+1) % nv) and ((vhi+2) % nv)
// Assign u,v scale to a unit length right vector.
fmag = zhypot(uvhi.v - uvlo.v, uvhi.u - uvlo.u);
if (fmag < 0.001) {
// mprintf(0,"Warning: fmag = %7.3f, using approximate u,v values\n",f2fl(fmag));
ruvmag.u = 256.0;
ruvmag.v = 256.0;
fuvmag.u = 256.0;
fuvmag.v = 256.0;
} else {
ruvmag.u = uvhi.v - uvlo.v;
ruvmag.v = uvlo.u - uvhi.u;
fuvmag.u = uvhi.u - uvlo.u;
fuvmag.v = uvhi.v - uvlo.v;
}
// Get pointers to our verts
vector *vv0 = &rp->verts[fp->face_verts[vlo]], *vv1 = &rp->verts[fp->face_verts[vhi]];
// Get forward vector from our edge
fvec = *vv1 - *vv0;
mag01 = vm_NormalizeVector(&fvec);
// Check for bad vector
if (mag01 < 0.001) {
OutrageMessageBox("U, V bogosity in room #%i, probably on face #%i. CLEAN UP YOUR MESS!", ROOMNUM(rp), facenum);
return;
}
// Get right vector from the cross product of the forward vec with the surface normal
rvec = fvec ^ fp->normal;
// Normalize uv values
ruvmag.u /= mag01;
ruvmag.v /= mag01;
fuvmag.u /= mag01;
fuvmag.v /= mag01;
// Compute UVs for each point
for (i = 1; i < nv - 1; i++) {
int fv = (vhi + i) % nv; // vert index in face
int rv = fp->face_verts[fv]; // vert index in room
// Get the vector for this edge
tvec = rp->verts[rv] - *vv0;
// Project the current edge onto our forward & right vectors
float rproj = tvec * rvec, fproj = tvec * fvec;
// Compute and assign UV values
fp->face_uvls[fv].u = uvlo.u + (ruvmag.u * rproj) + (fuvmag.u * fproj);
fp->face_uvls[fv].v = uvlo.v + (ruvmag.v * rproj) + (fuvmag.v * fproj);
}
}
// Stretches the UVS of a face
void StretchRoomUVs(room *rp, int facenum, int edge) {
roomUVL uv0, uv1;
int v0, v1;
face *fp = &rp->faces[facenum];
int i;
float saveu2[MAX_VERTS_PER_FACE], savev2[MAX_VERTS_PER_FACE];
for (i = 0; i < fp->num_verts; i++) {
saveu2[i] = fp->face_uvls[i].u2;
savev2[i] = fp->face_uvls[i].v2;
}
v0 = edge;
v1 = (v0 + 1) % rp->faces[facenum].num_verts;
uv0 = rp->faces[facenum].face_uvls[v0]; // copy uv AND l
uv1 = rp->faces[facenum].face_uvls[v1];
AssignUVsToFace(rp, facenum, &uv0, &uv1, v0, v1);
for (i = 0; i < fp->num_verts; i++) {
fp->face_uvls[i].u2 = saveu2[i];
fp->face_uvls[i].v2 = savev2[i];
}
}
// Scale all the UV values in a face from the center point (as defined by averaging the u & v values)
void ScaleFaceUVs(room *rp, int facenum, float scale) {
face *fp = &rp->faces[facenum];
int i;
float midu = 0, midv = 0;
for (i = 0; i < fp->num_verts; i++) {
midu += fp->face_uvls[i].u;
midv += fp->face_uvls[i].v;
}
midu /= fp->num_verts;
midv /= fp->num_verts;
for (i = 0; i < fp->num_verts; i++) {
fp->face_uvls[i].u = midu + (fp->face_uvls[i].u - midu) * scale;
fp->face_uvls[i].v = midv + (fp->face_uvls[i].v - midv) * scale;
}
World_changed = 1;
}