r_patch.c 26 KB

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