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-2000 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  * DESCRIPTION:
30  *  2D-in-3D video code
31  *
32  *---------------------------------------------------------------------
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #include "gl_opengl.h"
40 
41 #include "gl_intern.h"
42 #include "gl_struct.h"
43 #include "i_video.h"
44 #include "e6y.h"
45 
gld_Init8InGLMode(void)46 void gld_Init8InGLMode(void)
47 {
48   // clean up texture
49   if (vid_8ingl.texid)
50   {
51     glDeleteTextures(1, &vid_8ingl.texid);
52     vid_8ingl.texid = 0;
53   }
54 
55   // clean up PBOs
56   if (vid_8ingl.pboids[0])
57   {
58     GLEXT_glDeleteBuffersARB(2, vid_8ingl.pboids);
59     memset(vid_8ingl.pboids, 0, sizeof(vid_8ingl.pboids));
60   }
61 
62   // deallocate texture buffer
63   if (vid_8ingl.buf)
64   {
65     free(vid_8ingl.buf);
66     vid_8ingl.buf = NULL;
67   }
68 
69   gld_InitOpenGL(gl_compatibility);
70   gld_InitTextureParams();
71   gld_EnableTexture2D(GL_TEXTURE0_ARB, true);
72   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
73   glViewport(0, 0, REAL_SCREENWIDTH, REAL_SCREENHEIGHT);
74   gld_Set2DMode();
75 
76   vid_8ingl.width = gld_GetTexDimension(REAL_SCREENWIDTH);
77   vid_8ingl.height = gld_GetTexDimension(REAL_SCREENHEIGHT);
78   vid_8ingl.size = vid_8ingl.width * vid_8ingl.height * 4;
79 
80   vid_8ingl.fU1 = 0.0f;
81   vid_8ingl.fU2 = (float)REAL_SCREENWIDTH / (float)vid_8ingl.width;
82   vid_8ingl.fV1 = 0.0f;
83   vid_8ingl.fV2 = (float)REAL_SCREENHEIGHT / (float)vid_8ingl.height;
84 
85   glGenTextures(1, &vid_8ingl.texid);
86 
87   glBindTexture(GL_TEXTURE_2D, vid_8ingl.texid);
88 
89   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
90   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
91   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
92   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
93 
94   glTexImage2D(GL_TEXTURE_2D, 0, gl_tex_format,
95     vid_8ingl.width, vid_8ingl.height,
96     0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
97 
98   glBindTexture(GL_TEXTURE_2D, 0);
99 
100   // create 2 pixel buffer objects, you need to delete them when program exits.
101   // glBufferDataARB with NULL pointer reserves only memory space.
102   if (gl_arb_pixel_buffer_object)
103   {
104     GLEXT_glGenBuffersARB(2, vid_8ingl.pboids);
105     GLEXT_glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, vid_8ingl.pboids[0]);
106     GLEXT_glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, vid_8ingl.size, 0, GL_STREAM_DRAW_ARB);
107     GLEXT_glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, vid_8ingl.pboids[1]);
108     GLEXT_glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, vid_8ingl.size, 0, GL_STREAM_DRAW_ARB);
109     GLEXT_glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
110   }
111   else
112   {
113     vid_8ingl.buf = malloc(vid_8ingl.size);
114   }
115 }
116 
UpdatePixels(unsigned char * dst)117 void UpdatePixels(unsigned char* dst)
118 {
119   int x, y;
120 
121   unsigned int *pal = (unsigned int*)(vid_8ingl.colours +
122     256 * vid_8ingl.palette * 4);
123 
124   if (V_GetMode() == VID_MODE8)
125   {
126     for (y = 0; y < REAL_SCREENHEIGHT; y++)
127     {
128       byte *px = (((byte*)vid_8ingl.screen->pixels) + y * vid_8ingl.screen->pitch);
129       int *py = ((int*)dst) + y * vid_8ingl.width;
130       for (x = 0; x < REAL_SCREENWIDTH; x++)
131       {
132         *(int*)py = pal[*(byte*)px];
133         px += 1;
134         py += 1;
135       }
136     }
137   } else if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16)
138   {
139     unsigned int Rshift, Gshift, Bshift;
140     unsigned int Rmask, Gmask, Bmask;
141     SDL_PixelFormat *format = vid_8ingl.screen->format;
142 
143     Rmask = format->Rmask;
144     Gmask = format->Gmask;
145     Bmask = format->Bmask;
146 
147     Rshift = 16 - format->Rshift + format->Rloss;
148     Gshift =  8 - format->Gshift + format->Gloss;
149     Bshift =  0 - format->Bshift + format->Bloss;
150 
151     for (y = 0; y < REAL_SCREENHEIGHT; y++)
152     {
153       byte *px = (((byte*)vid_8ingl.screen->pixels) + y * vid_8ingl.screen->pitch);
154       int *py = ((int*)dst) + y * vid_8ingl.width;
155       for (x = 0; x < REAL_SCREENWIDTH; x++)
156       {
157         short color = *(short*)px;
158         *(int*)py =
159           ((color & Bmask) << Bshift) |
160           ((color & Gmask) << Gshift) |
161           ((color & Rmask) << Rshift);
162         px += 2;
163         py += 1;
164       }
165     }
166   }
167   else if (V_GetMode() == VID_MODE32)
168   {
169     for (y = 0; y < REAL_SCREENHEIGHT; y++)
170     {
171       byte *px = (((byte*)vid_8ingl.screen->pixels) + y * vid_8ingl.screen->pitch);
172       int *py = ((int*)dst) + y * vid_8ingl.width;
173       for (x = 0; x < REAL_SCREENWIDTH; x++)
174       {
175         *(int*)py = *(int*)px;
176         px += 4;
177         py += 1;
178       }
179     }
180   }
181 }
182 
gld_Draw8InGL(void)183 void gld_Draw8InGL(void)
184 {
185   if (gl_arb_pixel_buffer_object)
186   {
187     const int pboMode = 2;
188     unsigned char *ptr;
189     static int index = 0;
190     int nextIndex = 0; // pbo index used for next frame
191 
192     // increment current index first then get the next index
193     // "index" is used to copy pixels from a PBO to a texture object
194     // "nextIndex" is used to update pixels in a PBO
195     index = (index + 1) % 2;
196     if (pboMode == 1)        // with 1 PBO
197       nextIndex = index;
198     else if (pboMode == 2)   // with 2 PBO
199       nextIndex = (index + 1) % 2;
200 
201     // bind the texture and PBO
202     glBindTexture(GL_TEXTURE_2D, vid_8ingl.texid);
203     GLEXT_glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, vid_8ingl.pboids[index]);
204 
205     // copy pixels from PBO to texture object
206     // Use offset instead of ponter.
207 #if 0
208     glTexImage2D(GL_TEXTURE_2D, 0, gl_tex_format,
209       vid_8ingl.width, vid_8ingl.height,
210       0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
211 #else
212     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
213       vid_8ingl.width, vid_8ingl.height,
214       GL_BGRA, GL_UNSIGNED_BYTE, 0);
215 #endif
216 
217     // bind PBO to update pixel values
218     GLEXT_glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, vid_8ingl.pboids[nextIndex]);
219 
220     // map the buffer object into client's memory
221     // Note that glMapBufferARB() causes sync issue.
222     // If GPU is working with this buffer, glMapBufferARB() will wait(stall)
223     // for GPU to finish its job. To avoid waiting (stall), you can call
224     // first glBufferDataARB() with NULL pointer before glMapBufferARB().
225     // If you do that, the previous data in PBO will be discarded and
226     // glMapBufferARB() returns a new allocated pointer immediately
227     // even if GPU is still working with the previous data.
228     GLEXT_glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, vid_8ingl.size, 0, GL_STREAM_DRAW_ARB);
229 
230     ptr = GLEXT_glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);
231     if (ptr)
232     {
233       // update data directly on the mapped buffer
234       UpdatePixels(ptr);
235 
236       // release pointer to mapping buffer
237       GLEXT_glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
238     }
239 
240     // it is good idea to release PBOs with ID 0 after use.
241     // Once bound with 0, all pixel operations behave normal ways.
242     GLEXT_glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
243   }
244   else
245   {
246     glBindTexture(GL_TEXTURE_2D, vid_8ingl.texid);
247 
248     UpdatePixels(vid_8ingl.buf);
249 
250 #if 0
251     glTexImage2D(GL_TEXTURE_2D, 0, gl_tex_format,
252       vid_8ingl.width, vid_8ingl.height,
253       0, GL_BGRA, GL_UNSIGNED_BYTE, vid_8ingl.buf);
254 #else
255     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
256       vid_8ingl.width, vid_8ingl.height,
257       GL_BGRA, GL_UNSIGNED_BYTE, vid_8ingl.buf);
258 #endif
259   }
260 
261   glBegin(GL_TRIANGLE_STRIP);
262   {
263     glTexCoord2f(vid_8ingl.fU1, vid_8ingl.fV1);
264     glVertex2f(0.0f, 0.0f);
265 
266     glTexCoord2f(vid_8ingl.fU1, vid_8ingl.fV2);
267     glVertex2f(0.0f, (float)REAL_SCREENHEIGHT);
268 
269     glTexCoord2f(vid_8ingl.fU2, vid_8ingl.fV1);
270     glVertex2f((float)REAL_SCREENWIDTH, 0.0f);
271 
272     glTexCoord2f(vid_8ingl.fU2, vid_8ingl.fV2);
273     glVertex2f((float)REAL_SCREENWIDTH, (float)REAL_SCREENHEIGHT);
274   }
275   glEnd();
276 
277   // unbind texture
278   glBindTexture(GL_TEXTURE_2D, 0);
279 
280   glFinish();
281   SDL_GL_SwapBuffers();
282 }
283