rd_graphic.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright (c) 1993-2011 PrBoom developers (see AUTHORS)
  2. // Licence: GPLv2 or later (see COPYING)
  3. // Convert portable pixmap to Doom patch format
  4. #include "config.h"
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <ctype.h>
  9. #include "rd_util.h"
  10. #include "rd_palette.h"
  11. #include "rd_graphic.h"
  12. //
  13. // parseppm
  14. //
  15. // try to read a ppm file header and get width/height of image
  16. //
  17. static unsigned char *parseppm(char *ppm, size_t size, const char *file,
  18. int *width, int *height)
  19. {
  20. int maxcol, numpixels;
  21. char *pos = ppm;
  22. if (size < 2 || !(*pos++ == 'P' && *pos++ == '6'))
  23. die("Not a PPM: %s\n", file);
  24. // Ignore comments like "# Created by GIMP ..." in line 2
  25. if (*pos++ == '\n' && *pos == '#')
  26. while (*pos != '\n') pos++;
  27. numpixels = *width = strtol(pos, &pos, 0);
  28. numpixels *= *height = strtol(pos, &pos, 0);
  29. maxcol = strtol(pos, &pos, 0);
  30. if (maxcol != 255 || !isspace(*pos++))
  31. die("Invalid PPM header: %s\n", file);
  32. if (!numpixels || numpixels > (size-(ppm-pos))/3)
  33. die("Invalid PPM size: %s\n", file);
  34. return (unsigned char *)pos;
  35. }
  36. //
  37. // column_pixels_to_colours
  38. //
  39. // make an array of colour indices from a column of raw pixel data
  40. // (random access to which is easier while building a patch column)
  41. //
  42. static void pixels_to_colours(int *colours, unsigned char *pixels,
  43. int width, int height, int x)
  44. {
  45. int i = height;
  46. int *colour = colours;
  47. unsigned char *rgb = &pixels[3*x];
  48. while (--i>=0)
  49. {
  50. *colour = palette_getindex(rgb);
  51. colour++;
  52. rgb += 3*width;
  53. }
  54. }
  55. //
  56. // createcolumn
  57. //
  58. // make a doom patch column from an array of colour indices
  59. //
  60. static size_t createcolumn(unsigned char **column, int *colours, int height)
  61. {
  62. size_t size = 256, length = 0;
  63. unsigned char *data = xmalloc(size);
  64. int i, y, top, transparent, opaque;
  65. for (y = 0; y < height; )
  66. {
  67. // we are at the start of a new post
  68. top = y;
  69. // count transparent pixels above post and opaque pixels in it
  70. transparent = opaque = 0;
  71. for (; y < height && colours[y] == -1; y++) transparent++;
  72. for (; y < height && colours[y] >= 0; y++) opaque++;
  73. if (opaque > 0) // this post has pixels
  74. {
  75. while (size < length + opaque + 8)
  76. size *= 2, data = xrealloc(data, size);
  77. data[length++] = top + transparent; // column offset
  78. data[length++] = opaque; // length of column
  79. data[length++] = 0; // padding
  80. for (i = 0; i < opaque; i++)
  81. data[length++] = colours[top + transparent + i];
  82. data[length++] = 0; // more padding
  83. }
  84. }
  85. data[length++] = 0xff; // end of column
  86. *column = data;
  87. return length;
  88. }
  89. //
  90. // ppm_to_patch
  91. //
  92. // convert an 8-bit portable pixmap to doom's patch format
  93. // insert_x and insert_y are the graphic/sprite insertion point
  94. //
  95. size_t ppm_to_patch(void **lumpdata, const char *filename,
  96. int insert_x, int insert_y)
  97. {
  98. void *data;
  99. size_t size = read_or_die(&data, filename);
  100. int i, width, height, *column_colours;
  101. unsigned char *pixels, **columns, *patch;
  102. size_t *columnsizes, totalcolumnsize, offset;
  103. pixels = parseppm(data, size, filename, &width, &height);
  104. columns = xmalloc(width * sizeof(*columns));
  105. columnsizes = xmalloc(width * sizeof(*columnsizes));
  106. column_colours = xmalloc(height * sizeof(*column_colours));
  107. for (totalcolumnsize = i = 0; i < width; i++)
  108. {
  109. pixels_to_colours(column_colours, pixels, width, height, i);
  110. columnsizes[i] = createcolumn(&columns[i], column_colours, height);
  111. totalcolumnsize += columnsizes[i];
  112. }
  113. patch = xmalloc(8+4*width+totalcolumnsize);
  114. ((short *)patch)[0] = SHORT(width);
  115. ((short *)patch)[1] = SHORT(height);
  116. ((short *)patch)[2] = SHORT(insert_x);
  117. ((short *)patch)[3] = SHORT(insert_y);
  118. for (offset = 8+4*width, i = 0; i < width; i++)
  119. {
  120. ((int *)(patch+8))[i] = LONG(offset);
  121. offset += columnsizes[i];
  122. }
  123. for (offset = 8+4*width, i = 0; i < width; i++)
  124. {
  125. memmove(patch + offset, columns[i], columnsizes[i]);
  126. offset += columnsizes[i];
  127. free(columns[i]);
  128. }
  129. free(column_colours);
  130. free(columnsizes);
  131. free(columns);
  132. free(data);
  133. *lumpdata = patch;
  134. return 8+4*width+totalcolumnsize;
  135. }
  136. //
  137. // ppm_to_bitmap
  138. //
  139. // convert an 8-bit PPM to a raw map of Doom palette indices (for flats)
  140. //
  141. size_t ppm_to_bitmap(void **lumpdata, const char *filename)
  142. {
  143. void *data;
  144. size_t size = read_or_die(&data, filename);
  145. int i, j, width, height;
  146. unsigned char *pixels, *bitmap;
  147. pixels = parseppm(data, size, filename, &width, &height);
  148. bitmap = xmalloc(width * height);
  149. for (j = 0; j < height; j++)
  150. for (i = 0; i < width; i++)
  151. bitmap[width*j+i] = palette_getindex(&pixels[3*(width*j+i)]);
  152. free(data);
  153. *lumpdata = bitmap;
  154. return width * height;
  155. }