hedgewars/uRender.pas
changeset 4436 94c948a92759
parent 4420 6be946bcd17a
child 4451 1c342980b4aa
equal deleted inserted replaced
4366:d19adc635c99 4436:94c948a92759
       
     1 {$INCLUDE "options.inc"}
       
     2 unit uRender;
       
     3 
       
     4 interface
       
     5 
       
     6 uses SDLh, uTypes, GLunit;
       
     7 
       
     8 procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
       
     9 procedure DrawFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
       
    10 procedure DrawFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
       
    11 procedure DrawSprite (Sprite: TSprite; X, Y, Frame: LongInt);
       
    12 procedure DrawSprite2(Sprite: TSprite; X, Y, FrameX, FrameY: LongInt);
       
    13 procedure DrawSpriteClipped(Sprite: TSprite; X, Y, TopY, RightX, BottomY, LeftX: LongInt);
       
    14 procedure DrawTexture(X, Y: LongInt; Texture: PTexture; Scale: GLfloat = 1.0);
       
    15 procedure DrawTextureF(Texture: PTexture; Scale: GLfloat; X, Y, Frame, Dir, w, h: LongInt);
       
    16 procedure DrawRotatedTextureF(Texture: PTexture; Scale, OffsetX, OffsetY: GLfloat; X, Y, Frame, Dir, w, h: LongInt; Angle: real);
       
    17 procedure DrawRotated(Sprite: TSprite; X, Y, Dir: LongInt; Angle: real);
       
    18 procedure DrawRotatedF(Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real);
       
    19 procedure DrawRotatedTex(Tex: PTexture; hw, hh, X, Y, Dir: LongInt; Angle: real);
       
    20 procedure DrawCentered(X, Top: LongInt; Source: PTexture);
       
    21 procedure DrawLine(X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
       
    22 procedure DrawFillRect(r: TSDL_Rect);
       
    23 procedure DrawCircle(X, Y, Radius, Width: LongInt; r, g, b, a: Byte);
       
    24 procedure DrawHedgehog(X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real);
       
    25 procedure Tint(r, g, b, a: Byte); inline;
       
    26 procedure Tint(c: Longword); inline;
       
    27 
       
    28 var
       
    29     HHTexture: PTexture;
       
    30 
       
    31 implementation
       
    32 uses uVariables;
       
    33 var
       
    34     lastTint: Longword;
       
    35 
       
    36 procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt);
       
    37 begin
       
    38 r.y:= r.y + Height * Position;
       
    39 r.h:= Height;
       
    40 DrawFromRect(X, Y, @r, SpritesData[Sprite].Texture)
       
    41 end;
       
    42 
       
    43 procedure DrawFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
       
    44 begin
       
    45 DrawFromRect(X, Y, r^.w, r^.h, r, SourceTexture)
       
    46 end;
       
    47 
       
    48 procedure DrawFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture);
       
    49 var rr: TSDL_Rect;
       
    50     _l, _r, _t, _b: real;
       
    51     VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
       
    52 begin
       
    53 if (SourceTexture^.h = 0) or (SourceTexture^.w = 0) then exit;
       
    54 
       
    55 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
    56 if (abs(X) > W) and ((abs(X + W / 2) - W / 2) > cScreenWidth / cScaleFactor) then
       
    57     exit;
       
    58 if (abs(Y) > H) and ((abs(Y + H / 2 - (0.5 * cScreenHeight)) - H / 2) > cScreenHeight / cScaleFactor) then
       
    59     exit;
       
    60 
       
    61 rr.x:= X;
       
    62 rr.y:= Y;
       
    63 rr.w:= W;
       
    64 rr.h:= H;
       
    65 
       
    66 _l:= r^.x / SourceTexture^.w * SourceTexture^.rx;
       
    67 _r:= (r^.x + r^.w) / SourceTexture^.w * SourceTexture^.rx;
       
    68 _t:= r^.y / SourceTexture^.h * SourceTexture^.ry;
       
    69 _b:= (r^.y + r^.h) / SourceTexture^.h * SourceTexture^.ry;
       
    70 
       
    71 glBindTexture(GL_TEXTURE_2D, SourceTexture^.id);
       
    72 
       
    73 VertexBuffer[0].X:= X;
       
    74 VertexBuffer[0].Y:= Y;
       
    75 VertexBuffer[1].X:= rr.w + X;
       
    76 VertexBuffer[1].Y:= Y;
       
    77 VertexBuffer[2].X:= rr.w + X;
       
    78 VertexBuffer[2].Y:= rr.h + Y;
       
    79 VertexBuffer[3].X:= X;
       
    80 VertexBuffer[3].Y:= rr.h + Y;
       
    81 
       
    82 TextureBuffer[0].X:= _l;
       
    83 TextureBuffer[0].Y:= _t;
       
    84 TextureBuffer[1].X:= _r;
       
    85 TextureBuffer[1].Y:= _t;
       
    86 TextureBuffer[2].X:= _r;
       
    87 TextureBuffer[2].Y:= _b;
       
    88 TextureBuffer[3].X:= _l;
       
    89 TextureBuffer[3].Y:= _b;
       
    90 
       
    91 
       
    92 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
    93 glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
       
    94 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
    95 end;
       
    96 
       
    97 
       
    98 procedure DrawTexture(X, Y: LongInt; Texture: PTexture; Scale: GLfloat);
       
    99 begin
       
   100 
       
   101 glPushMatrix;
       
   102 glTranslatef(X, Y, 0);
       
   103 glScalef(Scale, Scale, 1);
       
   104 
       
   105 glBindTexture(GL_TEXTURE_2D, Texture^.id);
       
   106 
       
   107 glVertexPointer(2, GL_FLOAT, 0, @Texture^.vb);
       
   108 glTexCoordPointer(2, GL_FLOAT, 0, @Texture^.tb);
       
   109 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(Texture^.vb));
       
   110 
       
   111 glPopMatrix
       
   112 end;
       
   113 
       
   114 procedure DrawTextureF(Texture: PTexture; Scale: GLfloat; X, Y, Frame, Dir, w, h: LongInt);
       
   115 begin
       
   116     DrawRotatedTextureF(Texture, Scale, 0, 0, X, Y, Frame, Dir, w, h, 0)
       
   117 end;
       
   118 
       
   119 procedure DrawRotatedTextureF(Texture: PTexture; Scale, OffsetX, OffsetY: GLfloat; X, Y, Frame, Dir, w, h: LongInt; Angle: real);
       
   120 var ft, fb, fl, fr: GLfloat;
       
   121     hw, nx, ny: LongInt;
       
   122     VertexBuffer, TextureBuffer: array [0..3] of TVertex2f;
       
   123 begin
       
   124 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   125 if (abs(X) > W) and ((abs(X + dir * OffsetX) - W / 2) * cScaleFactor > cScreenWidth) then
       
   126     exit;
       
   127 if (abs(Y) > H) and ((abs(Y + OffsetY - (0.5 * cScreenHeight)) - W / 2) * cScaleFactor > cScreenHeight) then
       
   128     exit;
       
   129 
       
   130 glPushMatrix;
       
   131 glTranslatef(X, Y, 0);
       
   132 
       
   133 if Dir < 0 then
       
   134    glRotatef(Angle, 0, 0, -1)
       
   135 else
       
   136    glRotatef(Angle, 0, 0,  1);
       
   137 
       
   138 glTranslatef(Dir*OffsetX, OffsetY, 0);
       
   139 glScalef(Scale, Scale, 1);
       
   140 
       
   141 // Any reason for this call? And why only in t direction, not s?
       
   142 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
       
   143 
       
   144 if Dir < 0 then
       
   145     hw:= w div -2
       
   146 else
       
   147     hw:= w div 2;
       
   148 
       
   149 nx:= round(Texture^.w / w); // number of horizontal frames
       
   150 ny:= round(Texture^.h / h); // number of vertical frames
       
   151 
       
   152 ft:= (Frame mod ny) * Texture^.ry / ny;
       
   153 fb:= ((Frame mod ny) + 1) * Texture^.ry / ny;
       
   154 fl:= (Frame div ny) * Texture^.rx / nx;
       
   155 fr:= ((Frame div ny) + 1) * Texture^.rx / nx;
       
   156 
       
   157 glBindTexture(GL_TEXTURE_2D, Texture^.id);
       
   158 
       
   159 VertexBuffer[0].X:= -hw;
       
   160 VertexBuffer[0].Y:= w / -2;
       
   161 VertexBuffer[1].X:= hw;
       
   162 VertexBuffer[1].Y:= w / -2;
       
   163 VertexBuffer[2].X:= hw;
       
   164 VertexBuffer[2].Y:= w / 2;
       
   165 VertexBuffer[3].X:= -hw;
       
   166 VertexBuffer[3].Y:= w / 2;
       
   167 
       
   168 TextureBuffer[0].X:= fl;
       
   169 TextureBuffer[0].Y:= ft;
       
   170 TextureBuffer[1].X:= fr;
       
   171 TextureBuffer[1].Y:= ft;
       
   172 TextureBuffer[2].X:= fr;
       
   173 TextureBuffer[2].Y:= fb;
       
   174 TextureBuffer[3].X:= fl;
       
   175 TextureBuffer[3].Y:= fb;
       
   176 
       
   177 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   178 glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
       
   179 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   180 
       
   181 glPopMatrix
       
   182 end;
       
   183 
       
   184 procedure DrawRotated(Sprite: TSprite; X, Y, Dir: LongInt; Angle: real);
       
   185 begin
       
   186     DrawRotatedTex(SpritesData[Sprite].Texture,
       
   187         SpritesData[Sprite].Width,
       
   188         SpritesData[Sprite].Height,
       
   189         X, Y, Dir, Angle)
       
   190 end;
       
   191 
       
   192 procedure DrawRotatedF(Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real);
       
   193 begin
       
   194 glPushMatrix;
       
   195 glTranslatef(X, Y, 0);
       
   196 
       
   197 if Dir < 0 then
       
   198    glRotatef(Angle, 0, 0, -1)
       
   199 else
       
   200    glRotatef(Angle, 0, 0,  1);
       
   201 if Dir < 0 then glScalef(-1.0, 1.0, 1.0);
       
   202 
       
   203 DrawSprite(Sprite, -SpritesData[Sprite].Width div 2, -SpritesData[Sprite].Height div 2, Frame);
       
   204 
       
   205 glPopMatrix
       
   206 end;
       
   207 
       
   208 procedure DrawRotatedTex(Tex: PTexture; hw, hh, X, Y, Dir: LongInt; Angle: real);
       
   209 var VertexBuffer: array [0..3] of TVertex2f;
       
   210 begin
       
   211 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   212 if (abs(X) > 2 * hw) and ((abs(X) - hw) > cScreenWidth / cScaleFactor) then
       
   213     exit;
       
   214 if (abs(Y) > 2 * hh) and ((abs(Y - 0.5 * cScreenHeight) - hh) > cScreenHeight / cScaleFactor) then
       
   215     exit;
       
   216 
       
   217 glPushMatrix;
       
   218 glTranslatef(X, Y, 0);
       
   219 
       
   220 if Dir < 0 then
       
   221    begin
       
   222    hw:= - hw;
       
   223    glRotatef(Angle, 0, 0, -1);
       
   224    end else
       
   225    glRotatef(Angle, 0, 0,  1);
       
   226 
       
   227 
       
   228 glBindTexture(GL_TEXTURE_2D, Tex^.id);
       
   229 
       
   230 VertexBuffer[0].X:= -hw;
       
   231 VertexBuffer[0].Y:= -hh;
       
   232 VertexBuffer[1].X:= hw;
       
   233 VertexBuffer[1].Y:= -hh;
       
   234 VertexBuffer[2].X:= hw;
       
   235 VertexBuffer[2].Y:= hh;
       
   236 VertexBuffer[3].X:= -hw;
       
   237 VertexBuffer[3].Y:= hh;
       
   238 
       
   239 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   240 glTexCoordPointer(2, GL_FLOAT, 0, @Tex^.tb);
       
   241 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   242 
       
   243 glPopMatrix
       
   244 end;
       
   245 
       
   246 procedure DrawSprite (Sprite: TSprite; X, Y, Frame: LongInt);
       
   247 var row, col, numFramesFirstCol: LongInt;
       
   248 begin
       
   249 numFramesFirstCol:= SpritesData[Sprite].imageHeight div SpritesData[Sprite].Height;
       
   250 row:= Frame mod numFramesFirstCol;
       
   251 col:= Frame div numFramesFirstCol;
       
   252 DrawSprite2 (Sprite, X, Y, col, row);
       
   253 end;
       
   254 
       
   255 procedure DrawSpriteClipped(Sprite: TSprite; X, Y, TopY, RightX, BottomY, LeftX: LongInt);
       
   256 var r: TSDL_Rect;
       
   257 begin
       
   258 r.x:= 0;
       
   259 r.y:= 0;
       
   260 r.w:= SpritesData[Sprite].Width;
       
   261 r.h:= SpritesData[Sprite].Height;
       
   262 
       
   263 if (X < LeftX) then
       
   264     r.x:= LeftX - X;
       
   265 if (Y < TopY) then
       
   266     r.y:= TopY - Y;
       
   267 
       
   268 if (Y + SpritesData[Sprite].Height > BottomY) then
       
   269     r.h:= BottomY - Y + 1;
       
   270 if (X + SpritesData[Sprite].Width > RightX) then
       
   271     r.w:= RightX - X + 1;
       
   272 
       
   273 dec(r.h, r.y);
       
   274 dec(r.w, r.x);
       
   275 
       
   276 DrawFromRect(X + r.x, Y + r.y, @r, SpritesData[Sprite].Texture)
       
   277 end;
       
   278 
       
   279 procedure DrawSprite2(Sprite: TSprite; X, Y, FrameX, FrameY: LongInt);
       
   280 var r: TSDL_Rect;
       
   281 begin
       
   282     r.x:= FrameX * SpritesData[Sprite].Width;
       
   283     r.w:= SpritesData[Sprite].Width;
       
   284     r.y:= FrameY * SpritesData[Sprite].Height;
       
   285     r.h:= SpritesData[Sprite].Height;
       
   286     DrawFromRect(X, Y, @r, SpritesData[Sprite].Texture)
       
   287 end;
       
   288 
       
   289 procedure DrawCentered(X, Top: LongInt; Source: PTexture);
       
   290 var scale: GLfloat;
       
   291 begin
       
   292     if (Source^.w + 20) > cScreenWidth then
       
   293         scale:= cScreenWidth / (Source^.w + 20)
       
   294     else
       
   295         scale:= 1.0;
       
   296     DrawTexture(X - round(Source^.w * scale) div 2, Top, Source, scale)
       
   297 end;
       
   298 
       
   299 procedure DrawLine(X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
       
   300 var VertexBuffer: array [0..3] of TVertex2f;
       
   301 begin
       
   302     glDisable(GL_TEXTURE_2D);
       
   303     glEnable(GL_LINE_SMOOTH);
       
   304 
       
   305     glPushMatrix;
       
   306     glTranslatef(WorldDx, WorldDy, 0);
       
   307     glLineWidth(Width);
       
   308 
       
   309     Tint(r, g, b, a);
       
   310     VertexBuffer[0].X:= X0;
       
   311     VertexBuffer[0].Y:= Y0;
       
   312     VertexBuffer[1].X:= X1;
       
   313     VertexBuffer[1].Y:= Y1;
       
   314 
       
   315     glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   316     glDrawArrays(GL_LINES, 0, Length(VertexBuffer));
       
   317     Tint($FF, $FF, $FF, $FF);
       
   318     
       
   319     glPopMatrix;
       
   320     
       
   321     glEnable(GL_TEXTURE_2D);
       
   322     glDisable(GL_LINE_SMOOTH);
       
   323 end;
       
   324 
       
   325 procedure DrawFillRect(r: TSDL_Rect);
       
   326 var VertexBuffer: array [0..3] of TVertex2f;
       
   327 begin
       
   328 // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   329 if (abs(r.x) > r.w) and ((abs(r.x + r.w / 2) - r.w / 2) * cScaleFactor > cScreenWidth) then
       
   330     exit;
       
   331 if (abs(r.y) > r.h) and ((abs(r.y + r.h / 2 - (0.5 * cScreenHeight)) - r.h / 2) * cScaleFactor > cScreenHeight) then
       
   332     exit;
       
   333 
       
   334 glDisable(GL_TEXTURE_2D);
       
   335 
       
   336 Tint($00, $00, $00, $80);
       
   337 
       
   338 VertexBuffer[0].X:= r.x;
       
   339 VertexBuffer[0].Y:= r.y;
       
   340 VertexBuffer[1].X:= r.x + r.w;
       
   341 VertexBuffer[1].Y:= r.y;
       
   342 VertexBuffer[2].X:= r.x + r.w;
       
   343 VertexBuffer[2].Y:= r.y + r.h;
       
   344 VertexBuffer[3].X:= r.x;
       
   345 VertexBuffer[3].Y:= r.y + r.h;
       
   346 
       
   347 glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   348 glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   349 
       
   350 Tint($FF, $FF, $FF, $FF);
       
   351 glEnable(GL_TEXTURE_2D)
       
   352 end;
       
   353 
       
   354 procedure DrawCircle(X, Y, Radius, Width: LongInt; r, g, b, a: Byte); 
       
   355 var
       
   356     i: LongInt;
       
   357     CircleVertex: array [0..359] of TVertex2f;
       
   358 begin
       
   359     for i := 0 to 359 do begin
       
   360         CircleVertex[i].X := X + Radius*cos(i*pi/180);
       
   361         CircleVertex[i].Y := Y + Radius*sin(i*pi/180);
       
   362     end;
       
   363     glDisable(GL_TEXTURE_2D);
       
   364     glEnable(GL_LINE_SMOOTH);
       
   365     glPushMatrix;
       
   366     glLineWidth(Width);
       
   367     Tint(r, g, b, a);
       
   368     glVertexPointer(2, GL_FLOAT, 0, @CircleVertex[0]);
       
   369     glDrawArrays(GL_LINE_LOOP, 0, 360);
       
   370     Tint($FF, $FF, $FF, $FF);
       
   371     glPopMatrix;
       
   372     glEnable(GL_TEXTURE_2D);
       
   373     glDisable(GL_LINE_SMOOTH);
       
   374 end;
       
   375 
       
   376 
       
   377 procedure DrawHedgehog(X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real);
       
   378 const VertexBuffer: array [0..3] of TVertex2f = (
       
   379         (x: -16; y: -16),
       
   380         (x:  16; y: -16),
       
   381         (x:  16; y:  16),
       
   382         (x: -16; y:  16));
       
   383 var l, r, t, b: real;
       
   384     TextureBuffer: array [0..3] of TVertex2f;
       
   385 begin
       
   386     // don't draw anything outside the visible screen space (first check fixes some sprite drawing, e.g. hedgehogs)
       
   387     if (abs(X) > 32) and ((abs(X) - 16) * cScaleFactor > cScreenWidth) then
       
   388         exit;
       
   389     if (abs(Y) > 32) and ((abs(Y - 0.5 * cScreenHeight) - 16) * cScaleFactor > cScreenHeight) then
       
   390         exit;
       
   391 
       
   392     t:= Pos * 32 / HHTexture^.h;
       
   393     b:= (Pos + 1) * 32 / HHTexture^.h;
       
   394 
       
   395     if Dir = -1 then
       
   396     begin
       
   397     l:= (Step + 1) * 32 / HHTexture^.w;
       
   398     r:= Step * 32 / HHTexture^.w
       
   399     end else
       
   400     begin
       
   401     l:= Step * 32 / HHTexture^.w;
       
   402     r:= (Step + 1) * 32 / HHTexture^.w
       
   403     end;
       
   404 
       
   405 
       
   406     glPushMatrix();
       
   407     glTranslatef(X, Y, 0);
       
   408     glRotatef(Angle, 0, 0, 1);
       
   409 
       
   410     glBindTexture(GL_TEXTURE_2D, HHTexture^.id);
       
   411 
       
   412     TextureBuffer[0].X:= l;
       
   413     TextureBuffer[0].Y:= t;
       
   414     TextureBuffer[1].X:= r;
       
   415     TextureBuffer[1].Y:= t;
       
   416     TextureBuffer[2].X:= r;
       
   417     TextureBuffer[2].Y:= b;
       
   418     TextureBuffer[3].X:= l;
       
   419     TextureBuffer[3].Y:= b;
       
   420 
       
   421     glVertexPointer(2, GL_FLOAT, 0, @VertexBuffer[0]);
       
   422     glTexCoordPointer(2, GL_FLOAT, 0, @TextureBuffer[0]);
       
   423     glDrawArrays(GL_TRIANGLE_FAN, 0, Length(VertexBuffer));
       
   424 
       
   425     glPopMatrix
       
   426 end;
       
   427 
       
   428 
       
   429 procedure Tint(r, g, b, a: Byte); inline;
       
   430 var nc: Longword;
       
   431 begin
       
   432 nc:= (a shl 24) or (b shl 16) or (g shl 8) or r;
       
   433 if nc = lastTint then
       
   434     exit;
       
   435 glColor4ub(r, g, b, a);
       
   436 lastTint:= nc;
       
   437 end;
       
   438 
       
   439 procedure Tint(c: Longword); inline;
       
   440 begin
       
   441 Tint(((c shr 16) and $FF), ((c shr 8) and $FF), (c and $FF), $FF);
       
   442 end;
       
   443 
       
   444 end.