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