JNR
laObject.cpp
1 /*
2 
3 Jump'n'Run Engine
4 http://www.atanaslaskov.com/jnr/
5 
6 BSD LICENSE
7 Copyright (c) 2007-2013, Atanas Laskov
8 All rights reserved.
9 
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
12 1. Redistributions of source code must retain the above copyright notice,
13 this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright notice,
15 this list of conditions and the following disclaimer in the documentation
16 and/or other materials provided with the distribution.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL ATANAS LASKOV BE LIABLE FOR ANY
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 */
29 
30 //
31 // FILE: laObject.cpp
32 //
33 // This base class begins the class hierarchy of all dynamic objects that placed in a level
34 //
35 // Copyright (C) 2007-2013 Atanas Laskov, <latanas@gmail.com>
36 //
37 #include "stdafx.h"
38 #include "Core-Level-JR.h"
39 
40 laTexture laObject::_texShadow;
41 
42 // Constructor
43 //
44 laObject::laObject()
45 {
46  _nNext_ID = 0;
47 
48  _strTSName[0]=0;
49  _pLevel = NULL;
50  _pTileset = NULL;
51  _pTSObject = NULL;
52  _nTSIndex = 0;
53 
54  //_pNestedObject = NULL;
55 
56  _outline = laOutline(M_TRUE, laColor(), 0.8);
57  _color = laColor(255,255,255);
58  _bLightOn = M_TRUE;
59 }
60 
61 // Destructor
62 laObject::~laObject(void)
63 {
64  //while( nestedGet() ) nestedRemove(M_TRUE);
65  //MSG("ssd");
66 
67  _nested_destroy();
68 }
69 
70 // Respawn. Revert object to its original state
71 //
72 void laObject::respawn()
73 {
74  ERRORLEVEL_BEGIN;
75 
76  _nested_destroy();
77 
78  if( _ai.isActive() ) _ai.reset();
79 
80  ERRORLEVEL_END;
81 }
82 
83 // Dynamicly create a new object
84 //
85 void laObject::create(laPoint3 pos)
86 {
87  ERRORLEVEL_BEGIN;
88 
89  _ptPivot.size = _pTSObject->getPoint("bounding-box");
90  _ptPivot = pos; // + laPoint3(((laElement*)_pObject)->getBoundingPos() - _ptPivot.size);
91 
92  ERRORLEVEL_END;
93 }
94 
95 // Load the object from file
96 //
97 void laObject::load(class laFileParser *fp)
98 {
99  ERRORLEVEL_BEGIN;
100  ASSERT(_pTileset, "Nil tileset");
101 
102  laEnvironment_win32* pCE = ((laEnvironment_win32*)::laSystemIntegrator::getEnvironment());
103  unsigned seg;
104  laPoint3 offset;
105 
106  //Get an object pointer from the tileset
107  _pTSObject = _pTileset->getElement(_nTSIndex);
108 
109  //Read the position of the object
110  //
111  fp->readUnsigned(&seg);
112  fp->readObj(&offset, M_FALSE);
113 
114  _ptPivot.x( M_UNIT*M_SEGW*seg + offset.x()*M_UNIT + M_UNIT/2.0 );
115  _ptPivot.y( offset.y()*M_UNIT );
116  _ptPivot.z( offset.z()*M_UNIT + M_UNIT/2.0 );
117 
118  //Lazy-load shadow texture
119  if(!_texShadow.id())
120  _texShadow.load("particle_generic.png", M_TEX_TMAP);
121 
122  // Setup bounding-box
123  //
124  if( _pTSObject->getModelCnt() )
125  {
126  _ptPivot.size = _pTSObject->getPoint("bounding-box");
127  }
128  else
129  {
130  //No models, set an arbitrary size
131  _ptPivot.size = laPoint3(M_UNIT/2.0, M_UNIT/2.0);
132  }
133 
134  // Set color
135  try{ _color = this->getObject()->getColor("color"); }
136  catch(laError_PropertyNotDefined&){
137  _color = laColor(255,255,255,255);
138  }
139 
140  // Load AI
141  //
142  try{
143  char* strAI = getObject()->getText("ai-type");
144 
145  laFileParser fp_ai( getObject()->getText("ai-type") );
146 
147  if(_pLevel->getObjCnt())
148  _ai.controllers(this, (aiController*)(_pLevel->getPlayer()), _pLevel->getGlobalPercepts() );
149  else
150  _ai.controllers(this, this, _pLevel->getGlobalPercepts() );
151 
152  _ai.load( &fp_ai );
153  _ai.activate();
154  }
155  catch(laError_PropertyNotDefined& p){
156  _ai.activate(M_FALSE);
157  }
158 
159  // For static objects shadow can be projected only 1ce,
160  // no need to do it on very frame
161  _ptPivot.projectShadow();
162 
163  ERRORLEVEL_END;
164 }
165 
166 // Prepare the tranformation matrix for drawing the object
167 //
168 void laObject::_offset(laRenderer *r, laPoint3 ptBasePos)
169 {
170  ERRORLEVEL_BEGIN;
171  PROFILE_REN(laObject__offset);
172 
173  // Note: This is a workover for the laState_Intro,
174  // where an object is created for the narrator, without link to the level
175  if(!_pLevel) return;
176 
177  // Get terrain offset and curviture
178  //
179  double dTileOffset = _pLevel->terrainZOffset_atPixel(_ptPivot.x());
180 
181  laPoint3 pos(0,0,dTileOffset);
182  pos += ptBasePos + _ptPivot;
183 
184  // Move and rotate geometry
185  //
186  r->transTranslate( pos + _ptPivot.ptGeometryOffset );
187 
188  ERRORLEVEL_END;
189 }
190 
191 void laObject::_rotation(laRenderer *r)
192 {
193  ERRORLEVEL_BEGIN;
194  PROFILE_REN(laObject__rotation);
195 
196  // Note: This is a workover for the laState_Intro,
197  // where an object is created for the narrator, without link to the level
198  if(!_pLevel) return;
199 
200  // Get terrain offset and curviture
201  //
202  double dTileAngle = _pLevel->terrainAngle_atPixel(_ptPivot.x());
203 
204  // Rotate geometry
205  //
206  r->transRotate(dTileAngle + _ptPivot.angleY, laPoint3(0,1,0));
207  r->transRotate(_ptPivot.angleX, laPoint3(1,0,0));
208  r->transRotate(_ptPivot.angleZ, laPoint3(0,0,1));
209 
210  ERRORLEVEL_END;
211 }
212 
213 void laObject::_offset_and_rotation(laRenderer *r, laPoint3 ptBasePos) {
214  PROFILE_REN(laObject__offset_and_rotation);
215  _offset(r, ptBasePos);
216  _rotation(r);
217 }
218 
219 void laObject::_set_style(laRenderer *r) {
220  PROFILE_REN(laObject__set_style);
221  r->styleSet(_color);
222  r->modeOutline(_outline);
223  //r->modeLight(_bLightOn);
224 }
225 
226 // Draw the object geometry
227 //
228 void laObject::drawGeometry(laRenderer *r, laPoint3 ptBasePos)
229 {
230  _set_style(r);
231 
232  r->transPush();
233  _offset(r, ptBasePos);
234  this->_draw_positioned(r); //< laObject derivatives can overload this method
235 
236  _rotation(r);
237  this->_draw_positioned_rotated(r);
238  r->transPop();
239 
240  this->_draw_notrans(r, ptBasePos); //< laObject derivatives can overload this method
241 }
242 
243 void laObject::_draw_positioned(laRenderer *r) {
244 }
245 
246 void laObject::_draw_positioned_rotated(laRenderer *r) {
247  _pTSObject->drawGeometry( r );
248 }
249 
250 void laObject::_draw_notrans(laRenderer *r, laPoint3 ptBasePos) {
251  _nested_draw(r, ptBasePos);
252 }
253 
254 // Draw the object's associated effects;
255 // this method also draws a pseudo-shadow projected beneath the object
256 //
257 void laObject::drawFx(laRenderer *r, laPoint3 ptBasePos)
258 {
259  r->transPush();
260  _offset(r, ptBasePos);
261  this->_drawFx_positioned(r); //< laObject derivatives can overload this method
262 
263  // NOTE: Rotation doesnt really matter for Fx; Don't calculate rot
264  //_rotation(r);
265  //this->_drawFx_positioned_rotated(r);
266  r->transPop();
267 
268  this->_drawFx_notrans(r, ptBasePos); //< laObject derivatives can overload this method
269 }
270 
271 void laObject::_drawFx_positioned(laRenderer *r) {
272  _draw_shadow_fx( r );
273  _pTSObject->drawFx( r );
274 }
275 
276 void laObject::_drawFx_positioned_rotated(laRenderer *r) {
277 }
278 
279 void laObject::_drawFx_notrans(laRenderer *r, laPoint3 ptBasePos) {
280  _nested_draw_fx(r, ptBasePos);
281 }
282 
283 // Draw the object's associated GUI
284 //
285 void laObject::drawInterface(laRenderer *r, laPoint3 ptBasePos) {
286  _nested_draw_interface(r, ptBasePos);
287 }
288 
289 // Draw a shadow under the object
290 //
291 void laObject::_draw_shadow_fx(laRenderer *r)
292 {
293  ERRORLEVEL_BEGIN;
294  PROFILE_REN(laObject__draw_shadow_fx);
295 
296  // Shadow pos
297  //
298  double w = M_MIN(M_UNIT, _ptPivot.size.x() * 0.9);
299  laPoint3 pt1( -w/2.0, _ptPivot.dShadowY - _ptPivot.y(), -w/2.0 );
300 
301  double distance = M_MIN(1, M_ABS(_ptPivot.dShadowY - _ptPivot.y())/(M_UNIT*6.0) );
302  unsigned alpha = (1-distance) * 220;
303 
304  // Draw shadow
305  //
306  static laPoint3 p[3] = { laPoint3(w,0,0), laPoint3(w,0,w), laPoint3(0,0,w) };
307  static laPoint2 uv[4] = { laPoint3(0,0), laPoint3(0,1), laPoint3(1,1), laPoint3(1,0) };
308 
309  laPoint3 *pquad = r->vquadsData(0);
310  *(pquad++) = pt1;
311  *(pquad++) = pt1 + p[0];
312  *(pquad++) = pt1 + p[1];
313  *(pquad++) = pt1 + p[2];
314 
315  r->styleSet(laColor(0,0,0,alpha));
316  _texShadow.use();
317  r->vquadsDraw(1, uv);
318 
319  //r->drawRect(pt1, laPoint3(w, 0, w), laPoint2(), laPoint2(1,1));
320 
321  // Draw messages
322  // NOTE: Messages are not drawn camera facing, and this can be fixed by doing rot( -camera_angy ),
323  // but it's nice the way it is
324  //
325  fxMessages.draw(r, laPoint3(0, -1.1*_ptPivot.size.y(), 0) );
326  ERRORLEVEL_END;
327 }
328 
329 void laObject::_execute_ai(laTimer &t)
330 {
331  ERRORLEVEL_BEGIN;
332  PROFILE_ANIM(laObject__execute_ai);
333 
334  // Perceive player distance
335  //
336  laPlayer *pPlayer = (laPlayer*)( getLevelObject()->getPlayer() );
337  laLine2 ln(pPlayer->getPosition(), _ptPivot);
338  double dPlayer = ln.lenght();
339 
340  _ai.perceive(P__PLAYER_DISTANCE, aiPerceptData(dPlayer));
341 
342  // Execute AI
343  _ai.execute(&t);
344  _ai.perceptsClear();
345 
346  ERRORLEVEL_END;
347 }
348 
349 // Animate the object
350 //
351 void laObject::animate(laTimer &t)
352 {
353  ERRORLEVEL_BEGIN;
354  PROFILE_ANIM(laObject_animate);
355 
356  // Animate pivot physics
357  // NOTE: It is best to keep this commented, as most object don't really need colision detection etc.
358  // Inherited objects that need it (e.g. laMovingCreature) should make this call for themselves
359  //
360  //_ptPivot.simulate(t);
361 
362  if(_ai.isActive()) this->_execute_ai(t);
363 
364  fxMessages.animate(t);
365 
366  _nested_animate(t);
367  //if(_pNestedObject)
368  // _pNestedObject->animate(t);
369 
370  ERRORLEVEL_END;
371 }
372 
373 void laObject::_nested_draw(laRenderer *r, laPoint3 ptBasePos)
374 {
375  ERRORLEVEL_BEGIN;
376  std::map<unsigned, laObject*>::iterator i;
377 
378  for(i = _mNestedObjects.begin(); i != _mNestedObjects.end(); i++){
379  (*i).second->drawGeometry(r, ptBasePos);
380  }
381 
382  ERRORLEVEL_END;
383 }
384 
385 void laObject::_nested_draw_fx(laRenderer *r, laPoint3 ptBasePos)
386 {
387  ERRORLEVEL_BEGIN;
388  std::map<unsigned, laObject*>::iterator i;
389 
390  for(i = _mNestedObjects.begin(); i != _mNestedObjects.end(); i++){
391  (*i).second->drawFx(r, ptBasePos);
392  }
393 
394  ERRORLEVEL_END;
395 }
396 
397 void laObject::_nested_draw_interface(laRenderer *r, laPoint3 ptBasePos)
398 {
399  ERRORLEVEL_BEGIN;
400  std::map<unsigned, laObject*>::iterator i;
401 
402  for(i = _mNestedObjects.begin(); i != _mNestedObjects.end(); i++){
403  (*i).second->drawInterface(r, ptBasePos);
404  }
405 
406  ERRORLEVEL_END;
407 }
408 
409 void laObject::_nested_animate(laTimer &t)
410 {
411  ERRORLEVEL_BEGIN;
412  std::map<unsigned, laObject*>::iterator i;
413 
414  for(i = _mNestedObjects.begin(); i != _mNestedObjects.end(); i++){
415  (*i).second->animate(t);
416  }
417 
418  ERRORLEVEL_END;
419 }
420 
421 void laObject::_nested_destroy()
422 {
423  ERRORLEVEL_BEGIN;
424  std::map<unsigned, laObject*>::iterator i;
425 
426  for(i = _mNestedObjects.begin(); i != _mNestedObjects.end(); i++){
427  delete (*i).second;
428  }
429  _mNestedObjects.clear();
430 
431  ERRORLEVEL_END;
432 }
Playable Character.
Definition: laPlayer.h:46
#define M_UNIT
Unit of 1 meter.
2D Point
Definition: laPoint_novec.h:41
Object outline properties.
Definition: laRenderer.h:66
Animated Text Effect.
Definition: fxMessages.h:64
2D line segment
Definition: laLine2.h:40
2D Texture
Definition: laTexture.h:45
#define M_ABS(a)
Return abs(a)
virtual void vquadsDraw(unsigned nQuads, laPoint2 *ar_uv=NULL, laColor *ar_color=NULL, M_BOOL bBillboards=M_FALSE, M_BOOL bUseColorArrays=M_FALSE)=0
Draw an array of VQ, starting with the psecified pointers (or the first VQ if null) ...
virtual void modeOutline(const laOutline &outline)
Set outline parameters.
Definition: laRenderer.h:174
Class aiController is an abstract class for behaviours which can be performed by objects.
Definition: aiController.h:41
Virtual interface for the Engine graphics renderer.
Definition: laRenderer.h:98
laPoint3 * vquadsData(unsigned nQuad, unsigned nCount=1)
Get a pointer to VQ vertex data.
Definition: laRenderer.h:278
#define M_TEX_TMAP
Transparent texture with an alpha channel.
File Parser.
Definition: laFileParser.h:41