r_patch.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  5. * PrBoom: a Doom port merged with LxDoom and LSDLDoom
  6. * based on BOOM, a modified and improved DOOM engine
  7. * Copyright (C) 1999 by
  8. * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
  9. * Copyright (C) 1999-2002 by
  10. * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. *-----------------------------------------------------------------------------*/
  30. #include "z_zone.h"
  31. #include "doomstat.h"
  32. #include "w_wad.h"
  33. #include "r_main.h"
  34. #include "r_sky.h"
  35. #include "r_bsp.h"
  36. #include "r_things.h"
  37. #include "p_tick.h"
  38. #include "i_system.h"
  39. #include "r_draw.h"
  40. #include "lprintf.h"
  41. #include "r_patch.h"
  42. #include <assert.h>
  43. // posts are runs of non masked source pixels
  44. typedef struct
  45. {
  46. byte topdelta; // -1 is the last post in a column
  47. byte length; // length data bytes follows
  48. } post_t;
  49. // column_t is a list of 0 or more post_t, (byte)-1 terminated
  50. typedef post_t column_t;
  51. //
  52. // Patches.
  53. // A patch holds one or more columns.
  54. // Patches are used for sprites and all masked pictures,
  55. // and we compose textures from the TEXTURE1/2 lists
  56. // of patches.
  57. //
  58. typedef struct
  59. {
  60. short width, height; // bounding box size
  61. short leftoffset; // pixels to the left of origin
  62. short topoffset; // pixels below the origin
  63. int columnofs[8]; // only [width] used
  64. } patch_t;
  65. //---------------------------------------------------------------------------
  66. // Re-engineered patch support
  67. //---------------------------------------------------------------------------
  68. static rpatch_t *patches = 0;
  69. static rpatch_t *texture_composites = 0;
  70. //---------------------------------------------------------------------------
  71. void R_InitPatches(void) {
  72. if (!patches)
  73. {
  74. patches = (rpatch_t*)malloc(numlumps * sizeof(rpatch_t));
  75. // clear out new patches to signal they're uninitialized
  76. memset(patches, 0, sizeof(rpatch_t)*numlumps);
  77. } else {
  78. memset(patches, 0, sizeof(rpatch_t)*numlumps);
  79. }
  80. if (!texture_composites)
  81. {
  82. texture_composites = (rpatch_t*)malloc(numtextures * sizeof(rpatch_t));
  83. // clear out new patches to signal they're uninitialized
  84. memset(texture_composites, 0, sizeof(rpatch_t)*numtextures);
  85. }
  86. }
  87. //---------------------------------------------------------------------------
  88. void R_FlushAllPatches(void) {
  89. int i;
  90. if (patches)
  91. {
  92. for (i=0; i < numlumps; i++)
  93. if (patches[i].locks > 0)
  94. I_Error("R_FlushAllPatches: patch number %i still locked",i);
  95. free(patches);
  96. patches = NULL;
  97. }
  98. if (texture_composites)
  99. {
  100. for (i=0; i<numtextures; i++)
  101. if (texture_composites[i].data)
  102. free(texture_composites[i].data);
  103. free(texture_composites);
  104. texture_composites = NULL;
  105. }
  106. }
  107. //---------------------------------------------------------------------------
  108. int R_NumPatchWidth(int lump)
  109. {
  110. const rpatch_t *patch = R_CachePatchNum(lump);
  111. int width = patch->width;
  112. R_UnlockPatchNum(lump);
  113. return width;
  114. }
  115. //---------------------------------------------------------------------------
  116. int R_NumPatchHeight(int lump)
  117. {
  118. const rpatch_t *patch = R_CachePatchNum(lump);
  119. int height = patch->height;
  120. R_UnlockPatchNum(lump);
  121. return height;
  122. }
  123. //---------------------------------------------------------------------------
  124. static int getPatchIsNotTileable(const patch_t *patch) {
  125. int x=0, numPosts, lastColumnDelta = 0;
  126. const column_t *column;
  127. int cornerCount = 0;
  128. int hasAHole = 0;
  129. for (x=0; x<SHORT(patch->width); x++) {
  130. column = (const column_t *)((const byte *)patch + LONG(patch->columnofs[x]));
  131. if (!x) lastColumnDelta = column->topdelta;
  132. else if (lastColumnDelta != column->topdelta) hasAHole = 1;
  133. numPosts = 0;
  134. while (column->topdelta != 0xff) {
  135. // check to see if a corner pixel filled
  136. if (x == 0 && column->topdelta == 0) cornerCount++;
  137. else if (x == 0 && column->topdelta + column->length >= SHORT(patch->height)) cornerCount++;
  138. else if (x == SHORT(patch->width)-1 && column->topdelta == 0) cornerCount++;
  139. else if (x == SHORT(patch->width)-1 && column->topdelta + column->length >= SHORT(patch->height)) cornerCount++;
  140. if (numPosts++) hasAHole = 1;
  141. column = (const column_t *)((const byte *)column + column->length + 4);
  142. }
  143. }
  144. if (cornerCount == 4) return 0;
  145. return hasAHole;
  146. }
  147. //---------------------------------------------------------------------------
  148. static int getIsSolidAtSpot(const column_t *column, int spot) {
  149. if (!column) return 0;
  150. while (column->topdelta != 0xff) {
  151. if (spot < column->topdelta) return 0;
  152. if ((spot >= column->topdelta) && (spot <= column->topdelta + column->length)) return 1;
  153. column = (const column_t*)((const byte*)column + 3 + column->length + 1);
  154. }
  155. return 0;
  156. }
  157. //---------------------------------------------------------------------------
  158. // Used to determine whether a column edge (top or bottom) should slope
  159. // up or down for smoothed masked edges - POPE
  160. //---------------------------------------------------------------------------
  161. static int getColumnEdgeSlope(const column_t *prevcolumn, const column_t *nextcolumn, int spot) {
  162. int holeToLeft = !getIsSolidAtSpot(prevcolumn, spot);
  163. int holeToRight = !getIsSolidAtSpot(nextcolumn, spot);
  164. if (holeToLeft && !holeToRight) return 1;
  165. if (!holeToLeft && holeToRight) return -1;
  166. return 0;
  167. }
  168. //---------------------------------------------------------------------------
  169. static void createPatch(int id) {
  170. rpatch_t *patch;
  171. const int patchNum = id;
  172. const patch_t *oldPatch = (const patch_t*)W_CacheLumpNum(patchNum);
  173. const column_t *oldColumn, *oldPrevColumn, *oldNextColumn;
  174. int x, y;
  175. int pixelDataSize;
  176. int columnsDataSize;
  177. int postsDataSize;
  178. int dataSize;
  179. int *numPostsInColumn;
  180. int numPostsTotal;
  181. const unsigned char *oldColumnPixelData;
  182. int numPostsUsedSoFar;
  183. int edgeSlope;
  184. #ifdef RANGECHECK
  185. if (id >= numlumps)
  186. I_Error("createPatch: %i >= numlumps", id);
  187. #endif
  188. patch = &patches[id];
  189. // proff - 2003-02-16 What about endianess?
  190. patch->width = SHORT(oldPatch->width);
  191. patch->widthmask = 0;
  192. patch->height = SHORT(oldPatch->height);
  193. patch->leftoffset = SHORT(oldPatch->leftoffset);
  194. patch->topoffset = SHORT(oldPatch->topoffset);
  195. patch->isNotTileable = getPatchIsNotTileable(oldPatch);
  196. // work out how much memory we need to allocate for this patch's data
  197. pixelDataSize = (patch->width * patch->height + 4) & ~3;
  198. columnsDataSize = sizeof(rcolumn_t) * patch->width;
  199. // count the number of posts in each column
  200. numPostsInColumn = (int*)malloc(sizeof(int) * patch->width);
  201. numPostsTotal = 0;
  202. for (x=0; x<patch->width; x++) {
  203. oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x]));
  204. numPostsInColumn[x] = 0;
  205. while (oldColumn->topdelta != 0xff) {
  206. numPostsInColumn[x]++;
  207. numPostsTotal++;
  208. oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4);
  209. }
  210. }
  211. postsDataSize = numPostsTotal * sizeof(rpost_t);
  212. // allocate our data chunk
  213. dataSize = pixelDataSize + columnsDataSize + postsDataSize;
  214. patch->data = (unsigned char*)Z_Malloc(dataSize, PU_CACHE, (void **)&patch->data);
  215. memset(patch->data, 0, dataSize);
  216. // set out pixel, column, and post pointers into our data array
  217. patch->pixels = patch->data;
  218. patch->columns = (rcolumn_t*)((unsigned char*)patch->pixels + pixelDataSize);
  219. patch->posts = (rpost_t*)((unsigned char*)patch->columns + columnsDataSize);
  220. // sanity check that we've got all the memory allocated we need
  221. assert((((byte*)patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)patch->data) == dataSize);
  222. memset(patch->pixels, 0xff, (patch->width*patch->height));
  223. // fill in the pixels, posts, and columns
  224. numPostsUsedSoFar = 0;
  225. for (x=0; x<patch->width; x++) {
  226. oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x]));
  227. if (patch->isNotTileable) {
  228. // non-tiling
  229. if (x == 0) oldPrevColumn = 0;
  230. else oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x-1]));
  231. if (x == patch->width-1) oldNextColumn = 0;
  232. else oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x+1]));
  233. }
  234. else {
  235. // tiling
  236. int prevColumnIndex = x-1;
  237. int nextColumnIndex = x+1;
  238. while (prevColumnIndex < 0) prevColumnIndex += patch->width;
  239. while (nextColumnIndex >= patch->width) nextColumnIndex -= patch->width;
  240. oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex]));
  241. oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex]));
  242. }
  243. // setup the column's data
  244. patch->columns[x].pixels = patch->pixels + (x*patch->height) + 0;
  245. patch->columns[x].numPosts = numPostsInColumn[x];
  246. patch->columns[x].posts = patch->posts + numPostsUsedSoFar;
  247. while (oldColumn->topdelta != 0xff) {
  248. // set up the post's data
  249. patch->posts[numPostsUsedSoFar].topdelta = oldColumn->topdelta;
  250. patch->posts[numPostsUsedSoFar].length = oldColumn->length;
  251. patch->posts[numPostsUsedSoFar].slope = 0;
  252. edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta);
  253. if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_UP;
  254. else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_DOWN;
  255. edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+oldColumn->length);
  256. if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_UP;
  257. else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_DOWN;
  258. // fill in the post's pixels
  259. oldColumnPixelData = (const byte *)oldColumn + 3;
  260. for (y=0; y<oldColumn->length; y++) {
  261. patch->pixels[x * patch->height + oldColumn->topdelta + y] = oldColumnPixelData[y];
  262. }
  263. oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4);
  264. numPostsUsedSoFar++;
  265. }
  266. }
  267. if (1 || patch->isNotTileable) {
  268. const rcolumn_t *column, *prevColumn;
  269. // copy the patch image down and to the right where there are
  270. // holes to eliminate the black halo from bilinear filtering
  271. for (x=0; x<patch->width; x++) {
  272. //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]);
  273. column = R_GetPatchColumnClamped(patch, x);
  274. prevColumn = R_GetPatchColumnClamped(patch, x-1);
  275. if (column->pixels[0] == 0xff) {
  276. // force the first pixel (which is a hole), to use
  277. // the color from the next solid spot in the column
  278. for (y=0; y<patch->height; y++) {
  279. if (column->pixels[y] != 0xff) {
  280. column->pixels[0] = column->pixels[y];
  281. break;
  282. }
  283. }
  284. }
  285. // copy from above or to the left
  286. for (y=1; y<patch->height; y++) {
  287. //if (getIsSolidAtSpot(oldColumn, y)) continue;
  288. if (column->pixels[y] != 0xff) continue;
  289. // this pixel is a hole
  290. if (x && prevColumn->pixels[y-1] != 0xff) {
  291. // copy the color from the left
  292. column->pixels[y] = prevColumn->pixels[y];
  293. }
  294. else {
  295. // copy the color from above
  296. column->pixels[y] = column->pixels[y-1];
  297. }
  298. }
  299. }
  300. // verify that the patch truly is non-rectangular since
  301. // this determines tiling later on
  302. }
  303. W_UnlockLumpNum(patchNum);
  304. free(numPostsInColumn);
  305. }
  306. typedef struct {
  307. unsigned short patches;
  308. unsigned short posts;
  309. unsigned short posts_used;
  310. } count_t;
  311. static void switchPosts(rpost_t *post1, rpost_t *post2) {
  312. rpost_t dummy;
  313. dummy.topdelta = post1->topdelta;
  314. dummy.length = post1->length;
  315. dummy.slope = post1->slope;
  316. post1->topdelta = post2->topdelta;
  317. post1->length = post2->length;
  318. post1->slope = post2->slope;
  319. post2->topdelta = dummy.topdelta;
  320. post2->length = dummy.length;
  321. post2->slope = dummy.slope;
  322. }
  323. static void removePostFromColumn(rcolumn_t *column, int post) {
  324. int i;
  325. #ifdef RANGECHECK
  326. if (post >= column->numPosts)
  327. I_Error("removePostFromColumn: invalid post index");
  328. #endif
  329. if (post < column->numPosts)
  330. for (i=post; i<(column->numPosts-1); i++) {
  331. rpost_t *post1 = &column->posts[i];
  332. rpost_t *post2 = &column->posts[i+1];
  333. post1->topdelta = post2->topdelta;
  334. post1->length = post2->length;
  335. post1->slope = post2->slope;
  336. }
  337. column->numPosts--;
  338. }
  339. //---------------------------------------------------------------------------
  340. static void createTextureCompositePatch(int id) {
  341. rpatch_t *composite_patch;
  342. texture_t *texture;
  343. texpatch_t *texpatch;
  344. int patchNum;
  345. const patch_t *oldPatch;
  346. const column_t *oldColumn, *oldPrevColumn, *oldNextColumn;
  347. int i, x, y;
  348. int oy, count;
  349. int pixelDataSize;
  350. int columnsDataSize;
  351. int postsDataSize;
  352. int dataSize;
  353. int numPostsTotal;
  354. const unsigned char *oldColumnPixelData;
  355. int numPostsUsedSoFar;
  356. int edgeSlope;
  357. count_t *countsInColumn;
  358. #ifdef RANGECHECK
  359. if (id >= numtextures)
  360. I_Error("createTextureCompositePatch: %i >= numtextures", id);
  361. #endif
  362. composite_patch = &texture_composites[id];
  363. texture = textures[id];
  364. composite_patch->width = texture->width;
  365. composite_patch->height = texture->height;
  366. composite_patch->widthmask = texture->widthmask;
  367. composite_patch->leftoffset = 0;
  368. composite_patch->topoffset = 0;
  369. composite_patch->isNotTileable = 0;
  370. // work out how much memory we need to allocate for this patch's data
  371. pixelDataSize = (composite_patch->width * composite_patch->height + 4) & ~3;
  372. columnsDataSize = sizeof(rcolumn_t) * composite_patch->width;
  373. // count the number of posts in each column
  374. countsInColumn = (count_t *)calloc(sizeof(count_t), composite_patch->width);
  375. numPostsTotal = 0;
  376. for (i=0; i<texture->patchcount; i++) {
  377. texpatch = &texture->patches[i];
  378. patchNum = texpatch->patch;
  379. oldPatch = (const patch_t*)W_CacheLumpNum(patchNum);
  380. for (x=0; x<SHORT(oldPatch->width); x++) {
  381. int tx = texpatch->originx + x;
  382. if (tx < 0)
  383. continue;
  384. if (tx >= composite_patch->width)
  385. break;
  386. countsInColumn[tx].patches++;
  387. oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x]));
  388. while (oldColumn->topdelta != 0xff) {
  389. countsInColumn[tx].posts++;
  390. numPostsTotal++;
  391. oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4);
  392. }
  393. }
  394. W_UnlockLumpNum(patchNum);
  395. }
  396. postsDataSize = numPostsTotal * sizeof(rpost_t);
  397. // allocate our data chunk
  398. dataSize = pixelDataSize + columnsDataSize + postsDataSize;
  399. composite_patch->data = (unsigned char*)Z_Malloc(dataSize, PU_STATIC, (void **)&composite_patch->data);
  400. memset(composite_patch->data, 0, dataSize);
  401. // set out pixel, column, and post pointers into our data array
  402. composite_patch->pixels = composite_patch->data;
  403. composite_patch->columns = (rcolumn_t*)((unsigned char*)composite_patch->pixels + pixelDataSize);
  404. composite_patch->posts = (rpost_t*)((unsigned char*)composite_patch->columns + columnsDataSize);
  405. // sanity check that we've got all the memory allocated we need
  406. assert((((byte*)composite_patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)composite_patch->data) == dataSize);
  407. memset(composite_patch->pixels, 0xff, (composite_patch->width*composite_patch->height));
  408. numPostsUsedSoFar = 0;
  409. for (x=0; x<texture->width; x++) {
  410. // setup the column's data
  411. composite_patch->columns[x].pixels = composite_patch->pixels + (x*composite_patch->height);
  412. composite_patch->columns[x].numPosts = countsInColumn[x].posts;
  413. composite_patch->columns[x].posts = composite_patch->posts + numPostsUsedSoFar;
  414. numPostsUsedSoFar += countsInColumn[x].posts;
  415. }
  416. // fill in the pixels, posts, and columns
  417. for (i=0; i<texture->patchcount; i++) {
  418. texpatch = &texture->patches[i];
  419. patchNum = texpatch->patch;
  420. oldPatch = (const patch_t*)W_CacheLumpNum(patchNum);
  421. for (x=0; x<SHORT(oldPatch->width); x++) {
  422. int tx = texpatch->originx + x;
  423. if (tx < 0)
  424. continue;
  425. if (tx >= composite_patch->width)
  426. break;
  427. oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x]));
  428. {
  429. // tiling
  430. int prevColumnIndex = x-1;
  431. int nextColumnIndex = x+1;
  432. while (prevColumnIndex < 0) prevColumnIndex += SHORT(oldPatch->width);
  433. while (nextColumnIndex >= SHORT(oldPatch->width)) nextColumnIndex -= SHORT(oldPatch->width);
  434. oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex]));
  435. oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex]));
  436. }
  437. while (oldColumn->topdelta != 0xff) {
  438. rpost_t *post = &composite_patch->columns[tx].posts[countsInColumn[tx].posts_used];
  439. oldColumnPixelData = (const byte *)oldColumn + 3;
  440. oy = texpatch->originy;
  441. count = oldColumn->length;
  442. // the original renderer had several bugs which we reproduce here
  443. if (countsInColumn[tx].patches > 1) {
  444. // when there are multiple patches, then we need to handle the
  445. // column differently
  446. if (i == 0) {
  447. // draw first patch at original position, it will be partly
  448. // overdrawn below
  449. for (y=0; y<count; y++) {
  450. int ty = oy + oldColumn->topdelta + y;
  451. if (ty < 0)
  452. continue;
  453. if (ty >= composite_patch->height)
  454. break;
  455. composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y];
  456. }
  457. }
  458. // do the buggy clipping
  459. if ((oy + oldColumn->topdelta) < 0) {
  460. count += oy;
  461. oy = 0;
  462. }
  463. } else {
  464. // with a single patch only negative y origins are wrong
  465. oy = 0;
  466. }
  467. // set up the post's data
  468. post->topdelta = oldColumn->topdelta + oy;
  469. post->length = count;
  470. if ((post->topdelta + post->length) > composite_patch->height) {
  471. if (post->topdelta > composite_patch->height)
  472. post->length = 0;
  473. else
  474. post->length = composite_patch->height - post->topdelta;
  475. }
  476. if (post->topdelta < 0) {
  477. if ((post->topdelta + post->length) <= 0)
  478. post->length = 0;
  479. else
  480. post->length -= post->topdelta;
  481. post->topdelta = 0;
  482. }
  483. post->slope = 0;
  484. edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta);
  485. if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_TOP_UP;
  486. else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_TOP_DOWN;
  487. edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+count);
  488. if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_BOT_UP;
  489. else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_BOT_DOWN;
  490. // fill in the post's pixels
  491. for (y=0; y<count; y++) {
  492. int ty = oy + oldColumn->topdelta + y;
  493. if (ty < 0)
  494. continue;
  495. if (ty >= composite_patch->height)
  496. break;
  497. composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y];
  498. }
  499. oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4);
  500. countsInColumn[tx].posts_used++;
  501. assert(countsInColumn[tx].posts_used <= countsInColumn[tx].posts);
  502. }
  503. }
  504. W_UnlockLumpNum(patchNum);
  505. }
  506. for (x=0; x<texture->width; x++) {
  507. rcolumn_t *column;
  508. if (countsInColumn[x].patches <= 1)
  509. continue;
  510. // cleanup posts on multipatch columns
  511. column = &composite_patch->columns[x];
  512. i = 0;
  513. while (i<(column->numPosts-1)) {
  514. rpost_t *post1 = &column->posts[i];
  515. rpost_t *post2 = &column->posts[i+1];
  516. int length;
  517. if ((post2->topdelta - post1->topdelta) < 0)
  518. switchPosts(post1, post2);
  519. if ((post1->topdelta + post1->length) >= post2->topdelta) {
  520. length = (post1->length + post2->length) - ((post1->topdelta + post1->length) - post2->topdelta);
  521. if (post1->length < length) {
  522. post1->slope = post2->slope;
  523. post1->length = length;
  524. }
  525. removePostFromColumn(column, i+1);
  526. i = 0;
  527. continue;
  528. }
  529. i++;
  530. }
  531. }
  532. if (1 || composite_patch->isNotTileable) {
  533. const rcolumn_t *column, *prevColumn;
  534. // copy the patch image down and to the right where there are
  535. // holes to eliminate the black halo from bilinear filtering
  536. for (x=0; x<composite_patch->width; x++) {
  537. //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]);
  538. column = R_GetPatchColumnClamped(composite_patch, x);
  539. prevColumn = R_GetPatchColumnClamped(composite_patch, x-1);
  540. if (column->pixels[0] == 0xff) {
  541. // force the first pixel (which is a hole), to use
  542. // the color from the next solid spot in the column
  543. for (y=0; y<composite_patch->height; y++) {
  544. if (column->pixels[y] != 0xff) {
  545. column->pixels[0] = column->pixels[y];
  546. break;
  547. }
  548. }
  549. }
  550. // copy from above or to the left
  551. for (y=1; y<composite_patch->height; y++) {
  552. //if (getIsSolidAtSpot(oldColumn, y)) continue;
  553. if (column->pixels[y] != 0xff) continue;
  554. // this pixel is a hole
  555. if (x && prevColumn->pixels[y-1] != 0xff) {
  556. // copy the color from the left
  557. column->pixels[y] = prevColumn->pixels[y];
  558. }
  559. else {
  560. // copy the color from above
  561. column->pixels[y] = column->pixels[y-1];
  562. }
  563. }
  564. }
  565. // verify that the patch truly is non-rectangular since
  566. // this determines tiling later on
  567. }
  568. free(countsInColumn);
  569. }
  570. //---------------------------------------------------------------------------
  571. const rpatch_t *R_CachePatchNum(int id) {
  572. const int locks = 1;
  573. if (!patches)
  574. I_Error("R_CachePatchNum: Patches not initialized");
  575. #ifdef RANGECHECK
  576. if (id >= numlumps)
  577. I_Error("createPatch: %i >= numlumps", id);
  578. #endif
  579. if (!patches[id].data)
  580. createPatch(id);
  581. /* cph - if wasn't locked but now is, tell z_zone to hold it */
  582. if (!patches[id].locks && locks) {
  583. Z_ChangeTag(patches[id].data,PU_STATIC);
  584. #ifdef TIMEDIAG
  585. patches[id].locktic = gametic;
  586. #endif
  587. }
  588. patches[id].locks += locks;
  589. #ifdef SIMPLECHECKS
  590. if (!((patches[id].locks+1) & 0xf))
  591. lprintf(LO_DEBUG, "R_CachePatchNum: High lock on %8s (%d)\n",
  592. lumpinfo[id].name, patches[id].locks);
  593. #endif
  594. return &patches[id];
  595. }
  596. void R_UnlockPatchNum(int id)
  597. {
  598. const int unlocks = 1;
  599. #ifdef SIMPLECHECKS
  600. if ((signed short)patches[id].locks < unlocks)
  601. lprintf(LO_DEBUG, "R_UnlockPatchNum: Excess unlocks on %8s (%d-%d)\n",
  602. lumpinfo[id].name, patches[id].locks, unlocks);
  603. #endif
  604. patches[id].locks -= unlocks;
  605. /* cph - Note: must only tell z_zone to make purgeable if currently locked,
  606. * else it might already have been purged
  607. */
  608. if (unlocks && !patches[id].locks)
  609. Z_ChangeTag(patches[id].data, PU_CACHE);
  610. }
  611. //---------------------------------------------------------------------------
  612. const rpatch_t *R_CacheTextureCompositePatchNum(int id) {
  613. const int locks = 1;
  614. if (!texture_composites)
  615. I_Error("R_CacheTextureCompositePatchNum: Composite patches not initialized");
  616. #ifdef RANGECHECK
  617. if (id >= numtextures)
  618. I_Error("createTextureCompositePatch: %i >= numtextures", id);
  619. #endif
  620. if (!texture_composites[id].data)
  621. createTextureCompositePatch(id);
  622. /* cph - if wasn't locked but now is, tell z_zone to hold it */
  623. if (!texture_composites[id].locks && locks) {
  624. Z_ChangeTag(texture_composites[id].data,PU_STATIC);
  625. #ifdef TIMEDIAG
  626. texture_composites[id].locktic = gametic;
  627. #endif
  628. }
  629. texture_composites[id].locks += locks;
  630. #ifdef SIMPLECHECKS
  631. if (!((texture_composites[id].locks+1) & 0xf))
  632. lprintf(LO_DEBUG, "R_CacheTextureCompositePatchNum: High lock on %8s (%d)\n",
  633. textures[id]->name, texture_composites[id].locks);
  634. #endif
  635. return &texture_composites[id];
  636. }
  637. void R_UnlockTextureCompositePatchNum(int id)
  638. {
  639. const int unlocks = 1;
  640. #ifdef SIMPLECHECKS
  641. if ((signed short)texture_composites[id].locks < unlocks)
  642. lprintf(LO_DEBUG, "R_UnlockTextureCompositePatchNum: Excess unlocks on %8s (%d-%d)\n",
  643. textures[id]->name, texture_composites[id].locks, unlocks);
  644. #endif
  645. texture_composites[id].locks -= unlocks;
  646. /* cph - Note: must only tell z_zone to make purgeable if currently locked,
  647. * else it might already have been purged
  648. */
  649. if (unlocks && !texture_composites[id].locks)
  650. Z_ChangeTag(texture_composites[id].data, PU_CACHE);
  651. }
  652. //---------------------------------------------------------------------------
  653. const rcolumn_t *R_GetPatchColumnWrapped(const rpatch_t *patch, int columnIndex) {
  654. while (columnIndex < 0) columnIndex += patch->width;
  655. columnIndex %= patch->width;
  656. return &patch->columns[columnIndex];
  657. }
  658. //---------------------------------------------------------------------------
  659. const rcolumn_t *R_GetPatchColumnClamped(const rpatch_t *patch, int columnIndex) {
  660. if (columnIndex < 0) columnIndex = 0;
  661. if (columnIndex >= patch->width) columnIndex = patch->width-1;
  662. return &patch->columns[columnIndex];
  663. }
  664. //---------------------------------------------------------------------------
  665. const rcolumn_t *R_GetPatchColumn(const rpatch_t *patch, int columnIndex) {
  666. if (patch->isNotTileable) return R_GetPatchColumnClamped(patch, columnIndex);
  667. else return R_GetPatchColumnWrapped(patch, columnIndex);
  668. }